/*
 *   This file is part of ed_pvr.
 *
 *   ed_pvr is free software: you can redistribute it and/or modify
 *   it under the terms of the GNU General Public License as published by
 *   the Free Software Foundation, either version 2 of the License, or
 *   (at your option) any later version.
 *
 *   ed_pvr is distributed in the hope that it will be useful,
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *   GNU General Public License for more details.
 *
 *   You should have received a copy of the GNU General Public License
 *   along with ed_pvr.  If not, see <http://www.gnu.org/licenses/>.
 */

#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <inttypes.h>
#include <fcntl.h>
#include <unistd.h>
#include <memory.h>
#include <getopt.h>
#include <pthread.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <errno.h>
#include <signal.h>
#include <math.h>
#include <ctype.h>
#include <time.h>
#include <stdarg.h>
#include <sys/stat.h>
#include "device.h"
#include "utils.h"
#include "bitstream.h"
#include "mpegts.h"
#include "mpegts_io.h"
#include "protocol.h"

#ifdef USE_GLIB
#include <glib.h>
#endif


#define DEVICE_PRINT_STRING					"[DEV] "
#define URL_GET_SZ							1024
#define DEFAULT_LISTEN_PORT					9999
#define DEFAULT_LISTEN_IP					"0.0.0.0"
#define HTTP_OK_STR							"HTTP/1.0 200 OK\r\nContent-type: video/mpeg\r\n\r\n"
#define HTTP_OK_STR_LEN						45
#define __DATABUFFER_COUNT					5
#define __MEMLIST_BUFFER_COUNT				(21277 * TS_PACKET_SIZE)


#define ADAPT_RESERVED                  0x00
#define ADAPT_NO_FIELD_ONLY_PAYLOAD     0x01
#define ADAPT_FIELD_ONLY_NO_PAYLOAD     0x02
#define ADAPT_FIELD_AND_PAYLOAD         0x03


static const uint8_t AC3_START_CODE[2] 			= {0x0B, 0x77};
static const uint8_t MPEGAUDIO_START_CODE[2] 	= {0xFF, 0x07};
static const uint8_t MPEG2_START_CODE[3]		= {0x00, 0x00, 0x01};

#define MPEG2_PIC	0x00
#define MPEG2_SEQ	0xB3


#define H264_NAL_SLICE			0x01            // Slice, Non-IDR

#define H264_NAL_SDPA			0x02            // Slice Data Parition A
#define H264_NAL_SDPB			0x03            // Slice Data Parition B
#define H264_NAL_SDPC			0x04            // Slice Data Parition C
#define H264_NAL_IDR			0x05            // IDR

#define H264_NAL_SEI			0x06            // Supplemental Enhancement Information
#define H264_NAL_SPS			0x07            // Sequence Parameter Set
#define H264_NAL_PPS			0x08            // Pciture Parameter Set

#define H264_NAL_AUD			0x09            // Access Unit Delimiter
#define H264_NAL_SEQ_END		0x0A            // End of sequence
#define H264_NAL_STREAM_END		0x0B            // End of Stream

#define H264_PPIC_I				0x00
#define H264_PPIC_I_P			0x01
#define H264_PPIC_I_P_B			0x02
#define H264_PPIC_SI			0x03
#define H264_PPIC_SI_SP			0x04
#define H264_PPIC_I_SI			0x05
#define H264_PPIC_I_SI_P_SP		0x06
#define H264_PPIC_I_SI_P_SP_B	0x07

#define H264_SLICE_TYPE_P		0x00
#define H264_SLICE_TYPE_B		0x01
#define H264_SLICE_TYPE_I		0x02
#define H264_SLICE_TYPE_SP		0x03
#define H264_SLICE_TYPE_SI		0x04


#define H264_ASPECT_EXTENDED_SAR	255

struct h264_hrd_schedsel
{
	uint64_t bit_rate_value_minus1;
	uint64_t cpb_size_value_minus1;
	uint8_t cbr_flag;
};
typedef struct h264_hrd_schedsel H264_HRD_SCHEDSEL;

struct h264_hrd_params
{
	uint64_t cpb_cnt_minus1;
	uint8_t bit_rate_scale;
	uint8_t cpb_size_scale;
//    H264_HRD_SCHEDSEL * schedsel;
	H264_HRD_SCHEDSEL schedsel[32];

	uint8_t initial_cpb_removal_delay_length_minus1;
	uint8_t cpb_removal_delay_length_minus1;
	uint8_t dpb_output_delay_length_minus1;
	uint8_t time_offset_length;
};
typedef struct h264_hrd_params H264_HRD_PARAMS;

// Vui
struct h264_vui_params
{
	uint8_t aspect_ratio_info_present_flag;
	uint8_t aspect_ratio_idc;
	uint16_t sar_width;
	uint16_t sar_height;

	uint8_t overscan_info_present_flag;
	uint8_t overscan_appropriate_flag;

	uint8_t video_signal_type_present_flag;
	uint8_t video_format;
	uint8_t video_full_range_flag;
	uint8_t colour_description_present_flag;
	uint8_t colour_primaries;
	uint8_t transfer_characteristics;
	uint8_t matrix_coefficients;

	uint8_t chroma_loc_info_present_flag;
	uint64_t chroma_sample_loc_type_top_field;
	uint64_t chroma_sample_loc_type_bottom_field;

	uint8_t timing_info_present_flag;
	uint32_t num_units_in_tick;
	uint32_t time_scale;
	uint8_t fixed_frame_rate_flag;

	uint8_t nal_hrd_parameters_present_flag;
	H264_HRD_PARAMS *nal_hrd_parameters;

	uint8_t vcl_hrd_parameters_present_flag;
	H264_HRD_PARAMS *vcl_hrd_parameters;

	uint8_t low_delay_hrd_flag;

	uint8_t pic_struct_present_flag;
	uint8_t bitstream_restriction_flag;
	uint8_t motion_vectors_over_pic_boundaries_flag;
	uint64_t max_bytes_per_pic_denom;
	uint64_t max_bits_per_mb_denom;
	uint64_t log2_max_mv_length_horizontal;
	uint64_t log2_max_mv_length_vertical;
	uint64_t num_reorder_frames;
	uint64_t max_dec_frame_buffering;
};
typedef struct h264_vui_params H264_VUI_PARAMS;

// SPS
struct h264_seq_param_set
{
	uint8_t profile_idc;                            // u(8)
	uint8_t constraint_set0_flag;                   // u(1)
	uint8_t constraint_set1_flag;                   // u(1)
	uint8_t constraint_set2_flag;                   // u(1)
	uint8_t reserved_zero_5bits;                    // u(5)
	uint8_t level_idc;                              // u(8)
	uint64_t seq_parameter_set_id;                  // ue()

	uint64_t chroma_format_idc;
	uint8_t residual_colour_transform_flag;
	uint64_t bit_depth_luma;
	uint64_t bit_depth_chroma;
	uint8_t transform_bypass;
	uint8_t seq_scaling_matrix_present;

	uint64_t log2_max_frame_num_minus4;             // ue()
	uint64_t pic_order_cnt_type;                    // ue()
	uint64_t log2_max_pic_order_cnt_lsb_minus4;     // ue()
	uint8_t delta_pic_order_always_zero_flag;       // u(1)
	int64_t offset_for_non_ref_pic;                 // se()
	int64_t offset_for_top_to_bottom_field;         //
	uint64_t num_ref_frames_in_pic_order_cnt_cycle;
	int64_t offset_for_ref_frame[64];
	uint64_t num_ref_frames;
	uint8_t gaps_in_frame_num_value_allowed_flag;
	uint64_t pic_width_in_mbs_minus1;
	uint64_t pic_height_in_map_units_minus1;
	uint8_t frame_mbs_only_flag;
	uint8_t mb_adaptive_frame_field_flag;
	uint8_t direct_8x8_inference_flag;
	uint8_t frame_cropping_flag;
	uint64_t frame_crop_left_offset;
	uint64_t frame_crop_right_offset;
	uint64_t frame_crop_top_offset;
	uint64_t frame_crop_bottom_offset;
	uint8_t vui_parameters_present_flag;
	H264_VUI_PARAMS * vui_params;
	struct h264_seq_param_set *next;
};
typedef struct h264_seq_param_set H264_SEQ_PARAM_SET;

static const uint32_t AC3_FRAME_SIZE[38][4]=
{
	{ 64,   69,   96,  32   },
	{ 64,   70,   96,  32   },
	{ 80,   87,   120,  40  },
	{ 80,   88,   120,  40  },
	{ 96,   104,  144,  48  },
	{ 96,   105,  144,  48  },
	{ 112,  121,  168,  56  },
	{ 112,  122,  168,  56  },
	{ 128,  139,  192,  64  },
	{ 128,  140,  192,  64  },
	{ 160,  174,  240,  80  },
	{ 160,  175,  240,  80  },
	{ 192,  208,  288,  96  },
	{ 192,  209,  288,  96  },
	{ 224,  243,  336,  112 },
	{ 224,  244,  336,  112 },
	{ 256,  278,  384,  128 },
	{ 256,  279,  384,  128 },
	{ 320,  348,  480,  160 },
	{ 320,  349,  480,  160 },
	{ 384,  417,  576,  192 },
	{ 384,  418,  576,  192 },
	{ 448,  487,  672,  224 },
	{ 448,  488,  672,  224 },
	{ 512,  557,  768,  256 },
	{ 512,  558,  768,  256 },
	{ 640,  696,  960,  320 },
	{ 640,  697,  960,  320 },
	{ 768,  835,  1152, 384 },
	{ 768,  836,  1152, 384 },
	{ 896,  975,  1344, 448 },
	{ 896,  976,  1344, 448 },
	{ 1024, 1114, 1536, 512 },
	{ 1024, 1115, 1536, 512 },
	{ 1152, 1253, 1728, 576 },
	{ 1152, 1254, 1728, 576 },
	{ 1280, 1393, 1920, 640 },
	{ 1280, 1394, 1920, 640 },
};

static const uint32_t AC3_FSCOD[4]=
{
    48000,
    44100,
    32000,
    0,
};

static const uint32_t AAC_SAMPLING_FREQ_INDEX[15]=
{
	96000,
	88200,
	64000,
	48000,
	44100,
	32000,
	24000,
	22050,
	16000,
	12000,
	11025,
	8000,
	0,
	0,
	0,
};

#define AAC_FIXED_HEADER_SIZE	7
#define AAC_START_CODE_LEN		2

static const uint8_t AAC_START_CODE[AAC_START_CODE_LEN] = {0xFF, 0xF0};

// ********************  Forwards
int _h264_unescape03(uint8_t *, int);
H264_HRD_PARAMS * _h264_parse_hrd(BITSTREAM *);
H264_VUI_PARAMS * _h264_parse_vui(BITSTREAM *);
H264_SEQ_PARAM_SET * _h264_parse_sps(BITSTREAM *);
void _h264_free_sps(H264_SEQ_PARAM_SET *);

int _device_recording_fill_info(TUNER_WRITEPASS_STRUCT *);

void *_device_accept_thread(void *);
void _device_write_thread(gpointer, gpointer);
void *_device_read_thread(void *);
void *_device_command_thread(void *);
void *_device_process_thread(void *);

void _device_conn_pool_thread(gpointer, gpointer);

void _device_process_pat(DEVICE_STRUCT *, TUNER_STRUCT *, MPEGTS_PACKET *);
void _device_process_pmt(DEVICE_STRUCT *, TUNER_STRUCT *, MPEGTS_PACKET *);
uint8_t _device_process_payload(TUNER_STRUCT *, uint8_t *, uint32_t);
TUNER_INITPASS_STRUCT * _device_parse_incoming_connection(DEVICE_STRUCT *, int);
uint8_t _tuner_exit(TUNER_STRUCT *);
int _device_process_protocol_cmd(TUNER_WRITEPASS_STRUCT *);
int _device_handle_main_connect(DEVICE_CONN_STRUCT *);
int _device_handle_secondary_connect(DEVICE_STRUCT *);
int _device_do_tune_stream(DEVICE_STRUCT *, TUNER_INITPASS_STRUCT *);
void _dev_internal_printf(DEVICE_STRUCT *, const char *, ...);

//int _device_tuner_add_stream_data(TUNER_STRUCT *, uint16_t, uint8_t *, uint32_t);
TUNER_STREAM_STRUCT * _device_tuner_add_stream(TUNER_STRUCT *, uint16_t);
TUNER_STREAM_STRUCT * _device_tuner_get_stream(TUNER_STRUCT *, uint16_t);

int _device_tuner_stream_parse(TUNER_STREAM_STRUCT *);
UTILS_DATAPAIR_STRUCT * _device_tuner_stream_parse_get_data(TUNER_STREAM_STRUCT *);
DEVICE_CONN_STRUCT *_device_get_conn_thread(DEVICE_STRUCT *);

// ******************** Forwards end

int _h264_unescape03(uint8_t *buf, int len)
{
  uint8_t *dest;
  int i, j, skip;

  dest = malloc(len);
  if(! dest)
    return 0;

  j = i = skip = 0;
  while(i <= len-3)
  {
    if(buf[i] == 0 && buf[i+1] == 0 && buf[i+2] == 3)
    {
      dest[j] = dest[j+1] = 0;
      j += 2;
      i += 3;
      skip++;
    }
    else
    {
      dest[j] = buf[i];
      j++;
      i++;
    }
  }
  dest[j] = buf[len-2];
  dest[j+1] = buf[len-1];
  len -= skip;
  memcpy(buf, dest, len);
  free(dest);

  return len;
}

void _h264_free_sps(H264_SEQ_PARAM_SET *sps)
{
	if (sps)
	{
		if (sps->vui_params)
		{
			if (sps->vui_params->nal_hrd_parameters)
				free(sps->vui_params->nal_hrd_parameters);
			if (sps->vui_params->vcl_hrd_parameters)
				free(sps->vui_params->vcl_hrd_parameters);

			free(sps->vui_params);
		}
		free(sps);
	}
}


H264_HRD_PARAMS * _h264_parse_hrd(BITSTREAM *bitstream)
{
	int SchedSelIdx = 0;
	int8_t rc;
	H264_HRD_PARAMS * h = malloc(sizeof(H264_HRD_PARAMS));
	if (!h)
		printf("[H264] malloc error in h264_parse_hrd\n");

	memset(h, 0, sizeof(H264_HRD_PARAMS));
	h->cpb_cnt_minus1 = bits_get_ue_golomb(bitstream, &rc);
	h->bit_rate_scale = (uint8_t) bits_get_bit_count(bitstream, 4, &rc);
	h->cpb_size_scale = (uint8_t) bits_get_bit_count(bitstream, 4, &rc);
//        printf("[H264]   hrd->bit_rate_scale: %d\n", h->bit_rate_scale);
	for ( SchedSelIdx = 0; SchedSelIdx <= h->cpb_cnt_minus1; SchedSelIdx++ )
	{
		h->schedsel[SchedSelIdx].bit_rate_value_minus1 = bits_get_ue_golomb(bitstream, &rc);
		h->schedsel[SchedSelIdx].cpb_size_value_minus1 = bits_get_ue_golomb(bitstream, &rc);
		h->schedsel[SchedSelIdx].cbr_flag = (uint8_t) bits_get_bit_count(bitstream, 1, &rc);
		/*
		            printf("[H264]   hrd->shedsel[%d].bit_rate_value_minus1: %d\n", SchedSelIdx, h->schedsel[SchedSelIdx].bit_rate_value_minus1);
		            printf("[H264]   hrd->shedsel[%d].cpb_size_value_minus1: %d\n", SchedSelIdx, h->schedsel[SchedSelIdx].cpb_size_value_minus1);
		            printf("[H264]   hrd->shedsel[%d].cbr_flag: %d\n", SchedSelIdx, h->schedsel[SchedSelIdx].cbr_flag);
		            printf("[H264]   BR: %f\n", (h->schedsel[SchedSelIdx].bit_rate_value_minus1+1) * pow(2,  6+h->bit_rate_scale));
		 */
	}
	h->initial_cpb_removal_delay_length_minus1 = (uint8_t) bits_get_bit_count(bitstream, 5, &rc);
	h->cpb_removal_delay_length_minus1 = (uint8_t) bits_get_bit_count(bitstream, 5, &rc);
	h->dpb_output_delay_length_minus1 = (uint8_t) bits_get_bit_count(bitstream, 5, &rc);
	h->time_offset_length = (uint8_t) bits_get_bit_count(bitstream, 5, &rc);
	return h;
}



H264_VUI_PARAMS * _h264_parse_vui(BITSTREAM *bitstream)
{
	int8_t rc = 0;

	H264_VUI_PARAMS *v = calloc(1, sizeof(H264_VUI_PARAMS));

	if (!v)
		printf("[H264] malloc error in h264_parse_vui\n");


	v->aspect_ratio_info_present_flag = (uint8_t) bits_get_bit_count(bitstream, 1, &rc);
	if (v->aspect_ratio_info_present_flag)
	{
		v->aspect_ratio_idc = (uint8_t) bits_get_bit_count(bitstream, 8, &rc);
		if (v->aspect_ratio_idc == H264_ASPECT_EXTENDED_SAR)
		{
			v->sar_width = (uint16_t) bits_get_bit_count(bitstream, 16, &rc);
			v->sar_height = (uint16_t) bits_get_bit_count(bitstream, 16, &rc);
		}
	}

	v->overscan_info_present_flag = (uint8_t) bits_get_bit_count(bitstream, 1, &rc);
	if (v->overscan_info_present_flag)
		v->overscan_appropriate_flag = (uint8_t) bits_get_bit_count(bitstream, 1, &rc);

	v->video_signal_type_present_flag = (uint8_t) bits_get_bit_count(bitstream, 1, &rc);
	if (v->video_signal_type_present_flag)
	{
		v->video_format = (uint8_t) bits_get_bit_count(bitstream, 3, &rc);
		v->video_full_range_flag = (uint8_t) bits_get_bit_count(bitstream, 1, &rc);
		v->colour_description_present_flag = (uint8_t) bits_get_bit_count(bitstream, 1, &rc);

		if (v->colour_description_present_flag)
		{
			v->colour_primaries = (uint8_t) bits_get_bit_count(bitstream, 8, &rc);
			v->transfer_characteristics = (uint8_t) bits_get_bit_count(bitstream, 8, &rc);
			v->matrix_coefficients = (uint8_t) bits_get_bit_count(bitstream, 8, &rc);
		}
	}

	v->chroma_loc_info_present_flag = (uint8_t) bits_get_bit_count(bitstream, 1, &rc);
	if (v->chroma_loc_info_present_flag)
	{
		v->chroma_sample_loc_type_top_field = bits_get_ue_golomb(bitstream, &rc);
		v->chroma_sample_loc_type_bottom_field = bits_get_ue_golomb(bitstream, &rc);
	}

	v->timing_info_present_flag = (uint8_t) bits_get_bit_count(bitstream, 1, &rc);

	if (v->timing_info_present_flag)
	{
		v->num_units_in_tick = (uint32_t) bits_get_bit_count(bitstream, 32, &rc);
		v->time_scale = (uint32_t) bits_get_bit_count(bitstream, 32, &rc);
		v->fixed_frame_rate_flag = (uint8_t) bits_get_bit_count(bitstream, 1, &rc);
        //printf("ED ... %d, %d, %d\n", v->num_units_in_tick, v->time_scale, v->fixed_frame_rate_flag);
	}

	v->nal_hrd_parameters_present_flag = (uint8_t) bits_get_bit_count(bitstream, 1, &rc);
	if (v->nal_hrd_parameters_present_flag)
	{
		v->nal_hrd_parameters = _h264_parse_hrd(bitstream);
	}


	v->vcl_hrd_parameters_present_flag = (uint8_t) bits_get_bit_count(bitstream, 1, &rc);
	if (v->vcl_hrd_parameters_present_flag)
	{
		v->vcl_hrd_parameters = _h264_parse_hrd(bitstream);
	}

	if (v->nal_hrd_parameters_present_flag || v->vcl_hrd_parameters_present_flag)
		v->low_delay_hrd_flag = (uint8_t) bits_get_bit_count(bitstream, 1, &rc);

	v->pic_struct_present_flag = (uint8_t) bits_get_bit_count(bitstream, 1, &rc);
	v->bitstream_restriction_flag = (uint8_t) bits_get_bit_count(bitstream, 1, &rc);

	if (v->bitstream_restriction_flag)
	{
		v->motion_vectors_over_pic_boundaries_flag = (uint8_t) bits_get_bit_count(bitstream, 1, &rc);
		v->max_bytes_per_pic_denom = bits_get_ue_golomb(bitstream, &rc);
		v->max_bits_per_mb_denom = bits_get_ue_golomb(bitstream, &rc);
		v->log2_max_mv_length_horizontal = bits_get_ue_golomb(bitstream, &rc);
		v->log2_max_mv_length_vertical = bits_get_ue_golomb(bitstream, &rc);
		v->num_reorder_frames = bits_get_ue_golomb(bitstream, &rc);
		v->max_dec_frame_buffering = bits_get_ue_golomb(bitstream, &rc);
	}
	return v;
}

H264_SEQ_PARAM_SET * _h264_parse_sps(BITSTREAM *bitstream)
{
	H264_SEQ_PARAM_SET * sps = calloc(1, sizeof(H264_SEQ_PARAM_SET));

//	uint32_t _height = 0, _width = 0;
	int8_t rc = 0;

	if (!sps)
	{
		printf("[H264] malloc error in h264_parse_sps\n");
		return sps;
	}
//	    printf("[H264] NAL_PSI: Sequence parameter set: %x %x %x %x %x %x\n", bitstream->stream[0],
//	                                                                          bitstream->stream[1],
//	                                                                          bitstream->stream[2],
//	                                                                          bitstream->stream[3],
//	                                                                          bitstream->stream[4],
//	                                                                          bitstream->stream[5]);
	sps->profile_idc = (uint8_t) bits_get_bit_count(bitstream, 8, &rc);
	sps->constraint_set0_flag = (uint8_t) bits_get_bit_count(bitstream, 1, &rc);
	sps->constraint_set1_flag = (uint8_t) bits_get_bit_count(bitstream, 1, &rc);
	sps->constraint_set2_flag = (uint8_t) bits_get_bit_count(bitstream, 1, &rc);
	sps->reserved_zero_5bits = (uint8_t) bits_get_bit_count(bitstream, 5, &rc);
	sps->level_idc = (uint8_t) bits_get_bit_count(bitstream, 8, &rc);
	sps->seq_parameter_set_id = bits_get_ue_golomb(bitstream, &rc);
	
//    if(sps->profile_idc >= 100 )
	if ( sps->profile_idc == 100 || sps->profile_idc == 110 ||
	     sps->profile_idc == 122 || sps->profile_idc == 244 || sps->profile_idc == 44 ||
	     sps->profile_idc == 83  || sps->profile_idc == 86 )
	{
		sps->chroma_format_idc = bits_get_ue_golomb(bitstream, &rc);
		if (sps->chroma_format_idc == 3)
			sps->residual_colour_transform_flag = (uint8_t) bits_get_bit_count(bitstream, 1, &rc);
		sps->bit_depth_luma = bits_get_ue_golomb(bitstream, &rc);
		sps->bit_depth_chroma = bits_get_ue_golomb(bitstream, &rc);
		sps->transform_bypass = (uint8_t) bits_get_bit_count(bitstream, 1, &rc);
		sps->seq_scaling_matrix_present = (uint8_t) bits_get_bit_count(bitstream, 1, &rc);

		if (sps->seq_scaling_matrix_present)
		{
			int i, j;
			for (i = 0; i < 8; i++)
			{
				if ((uint8_t) bits_get_bit_count(bitstream, 1, &rc) == 1)
				{
					int last = 8, next = 8, size = (i < 6) ? 16 : 64;
					for (j = 0; j < size; j++)
					{
						if (next)
							next = (last + bits_get_se_golomb(bitstream, &rc)) & 0xff;
						last = next ? : last;
					}
				}
			}
		}
	}

	sps->log2_max_frame_num_minus4 = bits_get_ue_golomb(bitstream, &rc);
	sps->pic_order_cnt_type = bits_get_ue_golomb(bitstream, &rc);
	if (sps->pic_order_cnt_type == 0)
	{
		sps->log2_max_pic_order_cnt_lsb_minus4 = bits_get_ue_golomb(bitstream, &rc);
	}
	else if (sps->pic_order_cnt_type == 1)
	{
		int i;
		sps->delta_pic_order_always_zero_flag = (uint8_t) bits_get_bit_count(bitstream, 1, &rc);
		sps->offset_for_non_ref_pic = bits_get_se_golomb(bitstream, &rc);
		sps->offset_for_top_to_bottom_field = bits_get_se_golomb(bitstream, &rc);
		sps->num_ref_frames_in_pic_order_cnt_cycle = bits_get_ue_golomb(bitstream, &rc);
		for (i = 0; i < sps->num_ref_frames_in_pic_order_cnt_cycle; i++)
			sps->offset_for_ref_frame[i] = bits_get_se_golomb(bitstream, &rc);
	}
	sps->num_ref_frames = bits_get_ue_golomb(bitstream, &rc);
	sps->gaps_in_frame_num_value_allowed_flag = (uint8_t) bits_get_bit_count(bitstream, 1, &rc);
	sps->pic_width_in_mbs_minus1 = bits_get_ue_golomb(bitstream, &rc);
	sps->pic_height_in_map_units_minus1 = bits_get_ue_golomb(bitstream, &rc);
	sps->frame_mbs_only_flag = (uint8_t) bits_get_bit_count(bitstream, 1, &rc);
	if (!sps->frame_mbs_only_flag)
		sps->mb_adaptive_frame_field_flag = (uint8_t) bits_get_bit_count(bitstream, 1, &rc);
	sps->direct_8x8_inference_flag = (uint8_t) bits_get_bit_count(bitstream, 1, &rc);
	sps->frame_cropping_flag = (uint8_t) bits_get_bit_count(bitstream, 1, &rc);
	if (sps->frame_cropping_flag)
	{
		sps->frame_crop_left_offset = bits_get_ue_golomb(bitstream, &rc);
		sps->frame_crop_right_offset = bits_get_ue_golomb(bitstream, &rc);
		sps->frame_crop_top_offset = bits_get_ue_golomb(bitstream, &rc);
		sps->frame_crop_bottom_offset = bits_get_ue_golomb(bitstream, &rc);
	}
	sps->vui_parameters_present_flag = (uint8_t) bits_get_bit_count(bitstream, 1, &rc);

	sps->vui_params = NULL;
	if (sps->vui_parameters_present_flag)
	{
		sps->vui_params = _h264_parse_vui(bitstream);
		if (sps->vui_params && sps->vui_params->nal_hrd_parameters_present_flag)
		{
//			H264_HRD_PARAMS * h = sps->vui_params->nal_hrd_parameters;
//			nal_unit->bitrate = (h->schedsel[0].bit_rate_value_minus1 + 1) * pow(2, 6 + h->bit_rate_scale);
//			nal_unit->cpbsize = (h->schedsel[0].cpb_size_value_minus1 + 1) * pow(2, 4 + h->cpb_size_scale);

//		printf("HMM1: %f\n",  nal_unit->bitrate);
//		printf("HMM2: %f\n",  nal_unit->cpbsize);
//             nal_unit->bitrate = (h->schedsel[0].bit_rate_value_minus1+1) * pow(2, 6+h->bit_rate_scale) - 32;

//            printf("[H264]   BR: %f %f = %f\n", (double)(h->schedsel[0].bit_rate_value_minus1 + 1), (double)pow(2,  6 + h->bit_rate_scale), (h->schedsel[0].bit_rate_value_minus1 + 1) * pow(2,  6 + h->bit_rate_scale));
		}
	}
	return sps;
}

void _dev_internal_printf(DEVICE_STRUCT *dev, const char *format, ...)
{
	va_list ap;
	va_start(ap, format);

	if (dev && dev->cb_dev_printf)
	{
		(*dev->cb_dev_printf)(dev, format, ap);
	}
	else
	{
		vprintf(format, ap);
	}
	va_end(ap);

}
int32_t device_channel_get_count(DEVICE_STRUCT *dev)
{

	int32_t i = 0;
#ifdef USE_GLIB
	if (dev)
	{
		TUNER_CHANNEL_STRUCT * chan = dev->first_channel_list;

		if(dev->channel_filter &&
			dev->channel_filter->type == TUNER_CHANNEL_FILTER_INCLUDE &&
			file_exists(dev->channel_filter->filename) == 0)
		{
			device_reload_channel_filter(dev);
			return (int32_t)g_slist_length(dev->channel_filter->filter_glist);
		}

		while(chan)
		{
			i++;
			chan = chan->next;
		}
	}
#endif
	return i;
}

uint8_t device_channel_pid_valid(TUNER_STRUCT *tuner, uint16_t pid)
{
	if (tuner && pid)
	{
		int i;

		if (pid == PAT_PID || pid == NULL_PID)
			return 1;

		for (i=0; i < tuner->valid_count; i++)
		{
			if (tuner->valid_pids[i] == pid)
				return 1;
		}
	}
	return 0;
}

uint8_t device_channel_get_pid_type(TUNER_STRUCT *tuner, uint16_t pid)
{
	if (tuner && pid)
	{
		int i;

		if (pid == PAT_PID || pid == NULL_PID)
			return 0xFF;

		for (i=0; i < tuner->valid_count; i++)
		{
			if (tuner->valid_pids[i] == pid)
				return tuner->valid_pids_type[i];
		}
	}
	return 0;
}

void device_channel_print(TUNER_CHANNEL_STRUCT *  chan)
{
	if (chan)
	{
		DEVICE_STRUCT *device = NULL;
		int i;
		_dev_internal_printf(device, "[DEV-CHAN] Virtual Chan: %d, PGM: %" PRId64" (name: %s)\n", chan->virtual_channel, chan->program_num, chan->name);
		_dev_internal_printf(device, "[DEV-CHAN] SID: %d\n", chan->sid);
		if (chan->pid_count)
			_dev_internal_printf(device, "[DEV-CHAN] PID Count: %d\n", chan->pid_count);

		for(i=0; i < chan->pid_count; i++)
			_dev_internal_printf(device, "[DEV-CHAN] \t(%d) PID: %d (type: %d)\n", i, chan->pids[i], chan->pids_type[i]);

		if (chan->url_count)
			_dev_internal_printf(device, "[DEV-CHAN] URL Count: %d\n", chan->url_count);

		for(i=0; i < chan->url_count; i++)
			_dev_internal_printf(device, "[DEV-CHAN] \t(%d) URL: %s\n", i, chan->urls[i]);
		_dev_internal_printf(device, "[DEV-CHAN] Icon URL: %s\n", chan->icon_url);
	}
}

void device_channel_print_all(DEVICE_STRUCT *device)
{
	if (device)
	{
		int i;
		TUNER_CHANNEL_STRUCT * chan = device->first_channel_list;
		while(chan)
		{
			_dev_internal_printf(device, "[DEV-CHAN] Virtual Chan: %d, PGM: %" PRId64" (name: %s)\n", chan->virtual_channel, chan->program_num, chan->name);
			_dev_internal_printf(device, "[DEV-CHAN] SID: %d\n", chan->sid);
			if (chan->pid_count)
				_dev_internal_printf(device, "[DEV-CHAN] PID Count: %d\n", chan->pid_count);

			for(i=0; i < chan->pid_count; i++)
				_dev_internal_printf(device, "[DEV-CHAN] \t(%d) PID: %d (type: %d)\n", i, chan->pids[i], chan->pids_type[i]);

			if (chan->url_count)
				_dev_internal_printf(device, "[DEV-CHAN] URL Count: %d\n", chan->url_count);

			for(i=0; i < chan->url_count; i++)
				_dev_internal_printf(device, "[DEV-CHAN] \t(%d) URL: %s\n", i, chan->urls[i]);
			_dev_internal_printf(device, "[DEV-CHAN] Icon URL: %s\n", chan->icon_url);
			chan = chan->next;
		}
	}
}


void device_channel_reset_data(DEVICE_STRUCT *dev, uint64_t vchan, uint64_t pgm)
{
	if (dev)
	{
		TUNER_CHANNEL_STRUCT * chan = device_channel_get_struct(dev, vchan, pgm);
		if (chan)
		{
			TUNER_CHANNEL_STRUCT *tmp = chan->next;
			memset(chan, 0, sizeof(TUNER_CHANNEL_STRUCT));
			chan->next = tmp;
//			strncpy(chan->xmltv_id, xmltv, MAX_DEVNAME_SIZE);
		}
	}
}

void device_channel_clear(DEVICE_STRUCT *dev)
{
	if (dev)
	{
		TUNER_CHANNEL_STRUCT * chan = dev->first_channel_list, *del = NULL;
		while(chan)
		{
			del = chan;
			chan = chan->next;
			free(del);
		}
		dev->first_channel_list = dev->current_channel_list = NULL;
	}
}

void device_channel_add_xmltv_id(DEVICE_STRUCT *dev, uint64_t vchan, uint64_t pgm, char *xmltv)
{
	if (dev)
	{
		TUNER_CHANNEL_STRUCT * chan = device_channel_get_struct(dev, vchan, pgm);
		if (chan)
			strncpy(chan->xmltv_id, xmltv, MAX_DEVNAME_SIZE);
	}
}

void device_channel_add_url(DEVICE_STRUCT *dev, uint64_t vchan, uint64_t pgm, char *url)
{
	if (dev)
	{
		TUNER_CHANNEL_STRUCT * chan = device_channel_get_struct(dev, vchan, pgm);
		if (chan)
			chan->urls[chan->url_count++] = strdup(url);
	}
}

void device_channel_add_iconurl(DEVICE_STRUCT *dev, uint64_t vchan, uint64_t pgm, char *url)
{
	if (dev)
	{
		TUNER_CHANNEL_STRUCT * chan = device_channel_get_struct(dev, vchan, pgm);
		if (chan)
			strncpy(chan->icon_url, url, MAX_DEVNAME_SIZE);
	}
}

void device_channel_add_pid(DEVICE_STRUCT *dev, uint64_t vchan, uint64_t pgm, uint16_t pid, uint8_t type)
{
	if (dev)
	{
		TUNER_CHANNEL_STRUCT * chan = device_channel_get_struct(dev, vchan, pgm);
		if (chan)
		{
			chan->pids_type[chan->pid_count] = type;
			chan->pids[chan->pid_count++] = pid;
		}
	}
}

void device_channel_set_modulation(DEVICE_STRUCT *dev, uint64_t vchan, uint64_t pgm, uint8_t mtype)
{
	if (dev)
	{
		TUNER_CHANNEL_STRUCT * chan = device_channel_get_struct(dev, vchan, pgm);
		if (chan)
			chan->modulation_type = mtype;
	}
}

void device_channel_add_sid(DEVICE_STRUCT *dev, uint64_t vchan, uint64_t pgm, uint16_t sid)
{
	if (dev)
	{
		TUNER_CHANNEL_STRUCT * chan = device_channel_get_struct(dev, vchan, pgm);
		if (chan)
			chan->sid = sid;
	}
}

void device_channel_add_info(DEVICE_STRUCT *dev, uint64_t vchan, uint64_t pgm, char *info)
{
	if (dev)
	{
		TUNER_CHANNEL_STRUCT * chan = device_channel_get_struct(dev, vchan, pgm);
		if (chan)
			strncpy(chan->info, info, MAX_DEVNAME_SIZE);
	}
}
void device_channel_add_name(DEVICE_STRUCT *dev, uint64_t vchan, uint64_t pgm, char *name)
{
	if (dev)
	{
		TUNER_CHANNEL_STRUCT * chan = device_channel_get_struct(dev, vchan, pgm);
		if (chan)
			strncpy(chan->name, name, MAX_DEVNAME_SIZE);
	}
}

TUNER_CHANNEL_STRUCT * device_channel_add(DEVICE_STRUCT *dev, uint64_t vchan, uint64_t pgm)
{
	TUNER_CHANNEL_STRUCT * chan = device_channel_get_struct(dev, vchan, pgm);

	if (!chan && dev && vchan)
	{
		chan = calloc(1, sizeof(TUNER_CHANNEL_STRUCT));

		if (chan)
		{
			chan->virtual_channel = vchan;
			chan->program_num = pgm;

			if (!dev->first_channel_list)
			{
				dev->first_channel_list = dev->current_channel_list = chan;
			}
			else
			{
				dev->current_channel_list->next = chan;
				dev->current_channel_list = chan;
			}
			dev->channel_count++;
		}
	}
	return chan;
}

TUNER_CHANNEL_STRUCT * device_channel_get_struct(DEVICE_STRUCT *dev, uint64_t vchan, uint64_t pgm)
{
	TUNER_CHANNEL_STRUCT * ret = NULL;
	if (dev)
	{
		TUNER_CHANNEL_STRUCT * chan = dev->first_channel_list;
		while(chan)
		{
			if (chan->virtual_channel == vchan)
			{
				ret = chan;
				if (pgm && chan->program_num != pgm)
					ret = NULL;
				break;
			}
			chan = chan->next;
		}
	}
	return ret;
}

TUNER_STRUCT * device_tuner_find(DEVICE_STRUCT * device, int chan)
{
	TUNER_STRUCT * ret = NULL;
	if (device && chan > 0)
	{
		TUNER_STRUCT *tuner = device->first_tuner;
		printf("device_tuner_find locking tunerlock\n");
		while (pthread_mutex_trylock(&device->tunerlock) != 0)
		{
			printf("[DEVICE] waiting for tunerlock in device_tuner_find()\n");
			usleep(1000*2000);
		}
//		printf("device_tuner_find 1\n");

		while (tuner && !ret)
		{
			if (tuner->tuned_channel == chan)
			{
				ret = tuner;
				break;
			}
			tuner = tuner->next;
		}

//		printf("device_tuner_find 2\n");
		if (!ret)
		{
			tuner = device->first_tuner;
			while (tuner && !ret)
			{
				if (!tuner->tuned_channel)
					ret = tuner;
				else
					tuner = tuner->next;
			}
		}
		else
		{
			_dev_internal_printf(device, "[TUNER] Channel is tuned, re-using!\n");
		}

		if (tuner)
		{
			_dev_internal_printf(device, "[TUNER] [TID: %d] Found Unused Streamer, Name: %s, Tuner ID: %d\n\n", tuner->thread_id, tuner->name, tuner->id);
		}
		else
		{
			_dev_internal_printf(device, "[TUNER] NO STREAMER FOUND\n");
		}

//		printf("device_tuner_find unlocking tunerlock\n");
		pthread_mutex_unlock(&device->tunerlock);
//		printf("device_tuner_find end\n");
	}
//	_dev_internal_printf(device, "\ndevice_tuner_find -- end\n");
	return ret;
}

void device_tuner_add(DEVICE_STRUCT *dev, TUNER_STRUCT *tuner)
{
	if (dev && tuner)
	{
		tuner->next = NULL;
		if (!dev->first_tuner)
		{
			dev->first_tuner = dev->current_tuner = tuner;
		}
		else
		{
			dev->current_tuner->next = tuner;
			dev->current_tuner = tuner;
		}
		dev->tuner_count++;
	}
}

uint8_t _tuner_exit(TUNER_STRUCT * tuner)
{
    return TUNER_EXIT_MSG;
}

void device_destroy(DEVICE_STRUCT *device)
{
	if (device)
	{
		close(device->listen_socket);
		device->listen_socket = 0;
		g_thread_pool_free (device->glib_conn_thread_pool, TRUE, TRUE );

		while (device->listening)
		{

			printf("[DEVICE] Waiting for accept thread to die..\n");
			usleep(250*1000);
		}
	}
}

void device_tuner_destroy(TUNER_STRUCT *tuner)
{
	if (tuner)
	{
		if(tuner->write_thread_pool)
			g_thread_pool_free (tuner->write_thread_pool, TRUE, TRUE );
		tuner->alive = 0;
		while(tuner->read_thread)
			usleep(1000);

		tuner->cb_write_data = _tuner_exit;

		while(tuner->writing > 0)
			usleep(1000);
	}
}

TUNER_STRUCT *device_tuner_init(uint8_t tuner_type)
{
	TUNER_STRUCT * tuner = calloc(1, sizeof(TUNER_STRUCT));
	if (tuner)
	{
		tuner->type = tuner_type;
		tuner->write_thread_count = 1;
		tuner->alive = 1;
		tuner->writing = -1;
		tuner->fix_stream = 1;
#ifdef USE_GLIB
		tuner->write_thread_pool = g_thread_pool_new(_device_write_thread, (gpointer *)tuner, -1, FALSE, NULL );
#endif
		pthread_mutex_init(&tuner->init_mutex, NULL);
		pthread_mutex_init(&tuner->write_thread_init_lock, NULL);

		pthread_create(&tuner->read_thread, NULL, _device_read_thread, (void*)tuner);
		pthread_create(&tuner->process_thread, NULL, _device_process_thread, (void*)tuner);
	}
	return tuner;
}

DEVICE_STRUCT *device_init(char *bindip, uint16_t bindport)
{
	DEVICE_STRUCT * device = calloc(1, sizeof(DEVICE_STRUCT));
	if (device)
	{
		char *date = NULL, *time = NULL;

		device->log = utils_log_init();

		if (bindip)
			device->bind_ip = strdup(bindip);
		else
			device->bind_ip = DEFAULT_LISTEN_IP;

		if (bindport)
			device->bind_port = bindport;
		else
			device->bind_port = DEFAULT_LISTEN_PORT;

		time = get_local_time();
		date = get_local_date();

		_dev_internal_printf(device, "[DEVICE] device_init, starting listen thread [%s - %s]\n",date, time);

		if (time)
			free(time);

		if (date)
			free(date);

		device->listen_socket = get_listen_socket(device->bind_ip, device->bind_port);

		if (device->listen_socket == -1)
		{
			free(device);
			return NULL;
		}

		device->channel_filter = calloc(1, sizeof(TUNER_CHANNEL_FILTER_STRUCT));
		device->glib_conn_thread_pool = g_thread_pool_new(_device_conn_pool_thread, (gpointer *)device, -1, FALSE, NULL );

		pthread_mutex_init(&device->thread_init_mutex, NULL);
		pthread_mutex_init(&device->tunerlock, NULL);
		pthread_mutex_init(&device->process_cmd_mutex, NULL);

		pthread_create(&device->listen_thread, NULL, _device_accept_thread, (void*)device);


		while(!device->listening)
		{
			usleep(100*1000);
		}
	}
	return device;
}

TUNER_INITPASS_STRUCT * _device_parse_incoming_connection(DEVICE_STRUCT * device, int sock)
{
	TUNER_INITPASS_STRUCT *ret = NULL;

	if (sock > 2)
	{
		uint8_t buf[URL_GET_SZ] = {0}, buf2[URL_GET_SZ] = {0};
		char *token = NULL, *token2 = NULL, *last = NULL;
		int bytes_read, i;

		bytes_read = get_string_from_socket(sock, &buf[0], URL_GET_SZ);

		if (bytes_read <= 0)
		{
			_dev_internal_printf(device, "[TUNER] Couldn't read from socket, closing (%s -- %d)\n", strerror(errno), errno);
			return NULL;
		}

		strncpy((char*)buf2, (char*)buf, URL_GET_SZ);

		ret = calloc(1, sizeof(TUNER_INITPASS_STRUCT));
		token = strtok((char *)buf, " ");

		if (buf[0] == 'S' && buf[1] == 'C' && buf[2] == 'A' && buf[3] == 'N')
		{
			ret->type = TUNER_STREAM_TYPE_SCAN;
		}
		else if (buf[0] == 'G' && buf[1] == 'E' && buf[2] == 'T')
		{
			char *params = NULL;
			// Stream over HTTP
			ret->cmd = PROTO_TUNE_AND_STREAM;

			for (i = 0; i < bytes_read; i++)
			{
				if (buf[i] == '\n')
				{
					buf[i] = '\0';
					break;
				}
			}
			token = strtok(NULL, " ");
			token2 = strtok(token, "/");

			while(token2)
			{
				last = token2;
				token2 = strtok(NULL, "/");
			}
//			printf("---- URL: %s\n", last);

			params = strstr(last, "&");
			if (params)
			{
				ret->url_params = strdup(params+1);
				params[0] = '\0';
//				printf("ch_str: %s, params: %s\n", last, ret->url_params);
			}

			ret->channel_num = strtol(last, (char **)NULL, 10);
			ret->type = TUNER_STREAM_TYPE_HTTP;
			printf("[TUNER] HTTP tune: %" PRId64" (t: 0x%x)\n", ret->channel_num, ret->type);
		}
		else if (buf[0] == 'e' && buf[1] == 'T' && buf[2] == 'U' && buf[3] == 'N'&&
				buf[4] == 'E' && buf[5] == 'R')
		{
			PROTOCOL_CMD_STRUCT *cmd = NULL;
			uint8_t _confirmation = PROTOCOL_INIT_GOOD;
			protocol_send_tuner_init_status(sock, _confirmation);
			cmd = protocol_get_cmd(sock);

//			_dev_internal_printf(device, "cmd: %d -- %d\n", cmd->cmd, cmd->dataptr_size);
			if (cmd)
			{
				ret->cmd = cmd->cmd;
				switch(cmd->cmd)
				{
					case PROTO_TUNE_AND_STREAM:
					{
						PROTOCOL_TUNE_STRUCT * _ptmp = (PROTOCOL_TUNE_STRUCT *)cmd->dataptr;
						if (_ptmp)
							ret->channel_num = _ptmp->channel_num;
						printf("[TUNER] tune_stream chan: %" PRId64" (sb: %" PRId64")\n", ret->channel_num, _ptmp->game_datetime);
//						memcpy(&ret->channel_num, cmd->dataptr, cmd->dataptr_size);
					}
					break;

					default:
					break;
				}
				ret->dataptr = cmd->dataptr;
				ret->datasz = cmd->dataptr_size;

				cmd->dataptr = NULL;
				cmd->dataptr_size = 0;

				protocol_free_cmd_struct(cmd);
			}
			ret->type = TUNER_STREAM_TYPE_PROTOCOL;
		}
		else
		{
			free(ret);
			ret = NULL;
		}
	}
	else
	{
		_dev_internal_printf(device, "socket null!\n");
	}
	return ret;
}

 void _device_process_pmt(DEVICE_STRUCT * dev, TUNER_STRUCT * tuner, MPEGTS_PACKET *packet)
{
	if (dev && tuner && packet)
	{
		if (tuner->ts_parser.pmt)
		{
			int i;
			uint8_t bad_pmt = 0;
			MPEGTS_MAP_ES *desc_es = tuner->ts_parser.pmt->first_es;
			MPEGTS_MAP_ES *pmt_es = NULL, *_es1 = NULL, *_es2 = NULL;


			if (tuner->reset_valid_pids)
			{
				for(i=0; i < MAX_VALID_PIDS; i++)
					tuner->valid_pids[i] = 0;
				tuner->valid_count = 0;

				tuner->reset_valid_pids = 0;
			}

//			mpegts_print_pmt(tuner->ts_parser.pmt);
			if (!tuner->pgm_num &&  tuner->ts_parser.pmt->program_number)
				tuner->pgm_num = tuner->ts_parser.pmt->program_number;

			if (tuner->pmt_pid)
			{
				int i;
				for (i=0; i < tuner->valid_count; i++)
					if (tuner->valid_pids[i] == tuner->pmt_pid)
						break;

				if (i >= tuner->valid_count)
					tuner->valid_pids[tuner->valid_count++] = tuner->pmt_pid;
			}


			while (desc_es)
			{
				pmt_es = NULL;
				bad_pmt = 0;
				uint8_t process_desc = 1;

				if (process_desc)
				{
//					uint8_t iso639_lang[4]  = {0};
					uint8_t tag=0, len=0;
					int z=0, x=0;
					TUNER_STREAM_STRUCT * strm = _device_tuner_get_stream(tuner, desc_es->pid);

//					printf("\tblah: %p %d %d, pid : %d\n", strm, z, desc_es->info_len, desc_es->pid);
//					while (strm && z < desc_es->info_len)
					while (z < desc_es->info_len)
					{
						tag = desc_es->descriptor[z++];
						len = desc_es->descriptor[z++];
//						printf("[DEVICE] [PID: 0x%x] [%d] Tag: 0x%x Len: %d\n", desc_es->pid, z, tag, len);
//						printf("PID: 0x%x\n", desc_es->pid);
						switch(tag)
						{
							case MPEGTS_PMT_DESC_VIDEO:
//								printf("\tVideo Desc\n");
							break;

							case MPEGTS_PMT_DESC_AUDIO:
//								printf("\tAudio Desc\n");
							break;

							case MPEGTS_PMT_DESC_REG:
//								printf("HMM: 0x%x 0x%x 0x%x 0x%x\n", desc_es->descriptor[z], desc_es->descriptor[z+1], desc_es->descriptor[z+2], desc_es->descriptor[z+3]);
								if (desc_es->descriptor[z] == MPEGTS_PMT_AC3_REG[0] && desc_es->descriptor[z+1] == MPEGTS_PMT_AC3_REG[1] &&
									desc_es->descriptor[z+2] == MPEGTS_PMT_AC3_REG[2] && desc_es->descriptor[z+3] == MPEGTS_PMT_AC3_REG[3])
								{
//									printf("\tReg Desc -- AC3 Audio\n");
								}
							break;

							case MPEGTS_PMT_DESC_DSALIGN:
//								printf("\tData Align Desc\n");
							break;

							case MPEGTS_PMT_DESC_CA:
//								printf("\tCond. Access Desc\n");
							break;

							case MPEGTS_PMT_DESC_ISO639_LANG:
							{
//								printf("\t(0x%x) ISO639 Lang Desc: ", desc_es->pid);

								if (!strm)
									strm = _device_tuner_add_stream(tuner, desc_es->pid);

								for(x=0; x < len; x++)
								{
									strm->iso639_lang[x] = desc_es->descriptor[z+x];
//									printf("%c", desc_es->descriptor[z+x]);
								}
//								printf("\n");
							}
							break;

							case MPEGTS_PMT_DESC_SMOOTH:
//								printf("\tSmoothing Desc\n");
							break;

							case MPEGTS_PMT_DESC_STD:
//								printf("\tSTD Desc\n");
							break;

							case MPEGTS_PMT_DESC_AC3:
							{
/*
								uint8_t tmp;
								uint8_t num_channels = 0;
								uint8_t langcod = 0, langcod2 = 0;
								uint8_t bsmod = 0;
								uint8_t mainid = 0;
								uint8_t priority = 0;

								tmp = (desc_es->descriptor[z] & 0xE0) >> 5;			 	// sample_rate_code
								tmp = (desc_es->descriptor[z++] & 0x1F); 					// bsid

								tmp = (desc_es->descriptor[z] & 0xFC) >> 2; 			// bit_rate_code
								tmp = (desc_es->descriptor[z++] & 0x3); 				// surround_mode

								bsmod = (desc_es->descriptor[z] & 0xE0) >> 5;			// bsmod
								num_channels = (desc_es->descriptor[z] & 0x1E) >> 1; 	// num_channels
								tmp = (desc_es->descriptor[z++] & 0x1); 				// full_svc

								langcod = (desc_es->descriptor[z++]); 					// langcod

								if (num_channels == 0)
									langcod2 = (desc_es->descriptor[z++]); 				// langcod

								if (bsmod < 2)
								{
									mainid = (desc_es->descriptor[z] & 0xE0) >> 5;		//mainid
									priority = (desc_es->descriptor[z++] & 0x18) >> 3;		//mainid
								}
								else
									tmp = (desc_es->descriptor[z++]); 					// elseasvcflags

								printf("\tAC3 Desc, Len: %d\n", len);
*/
							}
							break;

							case MPEGTS_PMT_DESC_CAPTION:
//								printf("\tCaption Desc\n");
							break;

							case MPEGTS_PMT_DESC_AVC_VIDEO:
//								printf("\tAVC Desc\n");
							break;

							default:
//								printf("\tUnprocessed Desc: 0x%x, Len: %d\n", tag, len);
							break;
						}
						z += len;
//						printf("0x%02x ", desc_es->descriptor[z]);
					}
//					printf("\n");
				}

//				printf("ES Type: 0x%x\n", desc_es->stream_type);

				switch (desc_es->stream_type)
				{
					case MPEGTS_STREAM_TYPE_SOMETHING:		// MPEG2 Video
					case MPEGTS_STREAM_TYPE_ISO13818_V:		// MPEG2 Video
					case MPEGTS_STREAM_TYPE_ISO14496_10:	// H264 Video
						if (!tuner->video_es_type)
						{
//							tuner->video_pid = desc_es->pid;
							tuner->video_es_type = desc_es->stream_type;
						}
					case MPEGTS_STREAM_TYPE_ISO13818_7:		// AAC Audio
						if (desc_es->stream_type == MPEGTS_STREAM_TYPE_ISO13818_7)
						{
//							printf("AAC -- %d\n", desc_es->info_len);
						}

					case MPEGTS_STREAM_TYPE_USER_DATA:		// AC3 Audio (usually)
						if (desc_es->stream_type == MPEGTS_STREAM_TYPE_USER_DATA)
						{
							if (!desc_es->info_len)
							{
								bad_pmt = 1;
							}
						}
					case MPEGTS_STREAM_TYPE_ISO13818_3:		// MP2 Audio
						if (bad_pmt == 0)
						{
//							printf("HMM\n");
							for(i=0; i < MAX_VALID_PIDS; i++)
							{
								if (tuner->valid_pids[i] == desc_es->pid)
									break;
							}

							if (i >= MAX_VALID_PIDS)
							{
//								printf("[0x%x] from pmt, user_data len: %d\n", desc_es->pid, desc_es->info_len);
//								_dev_internal_printf(dev, "[DEV] Adding PID to valid list: %02x (%d)\n", desc_es->pid, tuner->valid_count);
//								if (desc_es->stream_type == MPEGTS_STREAM_TYPE_USER_DATA)

								tuner->valid_pids_type[tuner->valid_count] = desc_es->stream_type;
								tuner->valid_pids[tuner->valid_count++] = desc_es->pid;
							}

							pmt_es = desc_es;
						}
					break;

					case MPEGTS_STREAM_TYPE_SCTE35:			// Commerical Splicing, need todo
					break;

					default:
					break;
				}

				if (pmt_es)
				{
					MPEGTS_MAP_ES * newes = calloc(1, sizeof(MPEGTS_MAP_ES));

					if (newes)
					{
//						_dev_internal_printf(dev, "Adding to PMT, PID: %d, Type: 0x%x (i_len: %d)\n", pmt_es->pid, pmt_es->stream_type, pmt_es->info_len);
						memcpy(newes, pmt_es, sizeof(MPEGTS_MAP_ES));
						newes->descriptor = NULL;
						newes->next = NULL;

						if (pmt_es->info_len)
						{
							newes->descriptor = calloc(1, pmt_es->info_len);
							memcpy(newes->descriptor, pmt_es->descriptor, pmt_es->info_len);
						}

						if (!_es1)
						{
							_es1 = _es2 = newes;
						}
						else
						{
							_es2->next = newes;
							_es2 = newes;
						}
					}
				}

				desc_es = desc_es->next;
			}

			if (tuner->fix_stream)
			{
//				_dev_internal_printf(device, "Fixing PMT\n");
				mpegts_fix_pmt(packet->packet_data, TS_PACKET_SIZE,  tuner->ts_parser.pmt->pcr_pid, tuner->pgm_num, _es1);
			}

			pmt_es = _es1;
			while (pmt_es)
			{
				_es2 = pmt_es;
				pmt_es = pmt_es->next;
				if (_es2->descriptor)
					free(_es2->descriptor);
				free(_es2);
			}
		}
//		else
//			printf("PMT not set\n");

	}
}

 void _device_process_pat(DEVICE_STRUCT * device, TUNER_STRUCT * tuner, MPEGTS_PACKET *packet)
{
	if (device && tuner && packet)
	{
		TUNER_CHANNEL_STRUCT * _tuner_chan = device_channel_get_struct(device, tuner->tuned_channel, 0);
		MPEGTS_PAT_PROGRAM_STRUCT *pgm =  tuner->ts_parser.pat->first_program, *last = NULL;

		if (!tuner->pmt_pid)
		{
			if (tuner->cb_process_pat)
			{
				MPEGTS_PAT_PROGRAM_STRUCT *pgm  = (*tuner->cb_process_pat)(tuner->ts_parser.pat, _tuner_chan);
				if (pgm)
				{
					tuner->pmt_pid = pgm->pid;
					tuner->pgm_num = pgm->program_number;
					tuner->valid_pids[tuner->valid_count++] = tuner->pmt_pid;
					free(pgm);
				}
			}
			else
			{
				if (_tuner_chan)
				{
					uint16_t _count = 0;
					while(pgm)
					{
//						_dev_internal_printf(device, "PGM NUM: %d  --  (pid: 0x%x) %" PRId64"\n", pgm->program_number, pgm->pid, _tuner_chan->program_num);
						if (pgm->program_number && _tuner_chan->program_num == pgm->program_number)
						{
							tuner->pmt_pid = pgm->pid;
							tuner->pgm_num = pgm->program_number;
							tuner->valid_pids[tuner->valid_count++] = tuner->pmt_pid;
							last = NULL;
							_dev_internal_printf(device, "[DEVICE] Setting PMT PID1: %d (0x%x) [Chan: %" PRId64" PGM: %d], Packet Count: %" PRId64"\n", tuner->pmt_pid, tuner->pmt_pid, tuner->tuned_channel, pgm->program_number, tuner->packet_count);
							break;
						}
						last = pgm;
						pgm = pgm->next;
						_count++;
					}

					if (_count == 1 && last)
					{
						tuner->pgm_num = last->program_number;
						tuner->pmt_pid = last->pid;
						tuner->valid_pids[tuner->valid_count++] = tuner->pmt_pid;
						_dev_internal_printf(device, "[DEVICE] Setting PMT PID2: %d (0x%x) [Chan: %d PGM: %" PRId64"], Packet Count: %" PRId64"\n", tuner->pmt_pid, tuner->pmt_pid, tuner->tuned_channel, tuner->pgm_num, tuner->packet_count);
					}
//					tuner->ts_parser.pmt_pid = tuner->pmt_pid;
				}
				else
				{
					uint16_t _count = 0;

					while(pgm)
					{
//						_dev_internal_printf(device, "PGM NUM: %d\n", pgm->program_number);
						if (pgm->program_number)
						{
							tuner->pmt_pid = pgm->pid;
							tuner->pgm_num = pgm->program_number;
							tuner->valid_pids[tuner->valid_count++] = tuner->pmt_pid;
							last = NULL;
							_dev_internal_printf(device, "[DEVICE] Setting PMT PID3: %d (0x%x) [Chan: %d PGM: %d], Packet Count: %" PRId64"\n", tuner->pmt_pid, tuner->pmt_pid, tuner->tuned_channel, pgm->program_number, tuner->packet_count);
							break;
						}
						last = pgm;
						pgm = pgm->next;
						_count++;
					}

					if (_count == 1 && last)
					{
						tuner->pgm_num = last->program_number;
						tuner->pmt_pid = last->pid;
						tuner->valid_pids[tuner->valid_count++] = tuner->pmt_pid;
						_dev_internal_printf(device, "[DEVICE] Setting PMT PID4: %d (0x%x) [Chan: %d PGM: %" PRId64"], Packet Count: %" PRId64"\n", tuner->pmt_pid, tuner->pmt_pid, tuner->tuned_channel, tuner->pgm_num, tuner->packet_count);
					}
//					tuner->ts_parser.pmt_pid = tuner->pmt_pid;
				}
			}
			tuner->ts_parser.pmt_pid = tuner->pmt_pid;

		}
		else if (tuner->pmt_pid && !tuner->valid_count && _tuner_chan)
		{
			while(pgm)
			{
//				_dev_internal_printf(device, "PGM NUM: %d  --  (pid: 0x%x) %" PRId64"\n", pgm->program_number, pgm->pid, _tuner_chan->program_num);
				if (tuner->pmt_pid == pgm->pid)
				{
					tuner->ts_parser.pmt_pid = tuner->pmt_pid = pgm->pid;
					tuner->pmt_pid = pgm->pid;
					tuner->pgm_num = pgm->program_number;
					tuner->valid_pids[tuner->valid_count++] = tuner->pmt_pid;

					_dev_internal_printf(device, "[DEVICE] Setting PMT PID5: %d (0x%x) [Chan: %d PGM: %d], Packet Count: %" PRId64"\n", tuner->pmt_pid, tuner->pmt_pid, tuner->tuned_channel, pgm->program_number, tuner->packet_count);
					break;
				}
				pgm = pgm->next;
			}
		}
//		_dev_internal_printf(device, "3\n");


		if (tuner->fix_stream  && tuner->pmt_pid)
		{
//			_dev_internal_printf(device, "Fixing PAT\n");
			mpegts_fix_pat(packet->packet_data, TS_PACKET_SIZE, tuner->pmt_pid, tuner->pgm_num);
		}
	}
	else
		_dev_internal_printf(device, "_device_process_pat -- bad\n");
//	_dev_internal_printf(device, "_device_process_pat end\n");
}


 int8_t _device_process_payload_start(DEVICE_STRUCT * dev, TUNER_STRUCT * tuner, MPEGTS_PACKET *packet)
{
	int8_t ret = -1;
	int8_t rc;

	if (dev && tuner && packet)
	{
		uint8_t pmt_type = device_channel_get_pid_type(tuner, packet->pid);
//		printf("\tPID: 0x%02X, Type: 0x%x\n", packet->pid, pmt_type);
		if (tuner->pmt_pid && device_channel_pid_valid(tuner, packet->pid))
		{
			MPEGTS_PAYLOAD_START *psu = packet->payload_start_struct;
			BITSTREAM *bitstream = packet->bitstream;
			uint8_t *data = packet->packet_data;
//			printf("VALID: PMT PID: 0x%02X, PID: 0x%02X, Valid: %d\n", tuner->pmt_pid, packet->pid, device_channel_pid_valid(tuner, packet->pid));

			// determine video frame type here
			if (bitstream && data && mpegts_streamtype_valid(psu->stream_id) == MPEGTS_TYPE_VIDEO)
			{
				uint8_t fr_type = 0;
				int i = (bitstream->bit_offset/8);
//				printf("\t\t !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!            VIDEO?\n");

				for (; i < TS_PACKET_SIZE - 5; i++)
				{
					if (data[i] == 0x00 && data[i+1] == 0x00 && data[i+2] == 0x01)
					{
						if (tuner->video_es_type == MPEGTS_STREAM_TYPE_ISO13818_V || tuner->video_es_type == MPEGTS_STREAM_TYPE_SOMETHING)
						{
							if (data[i+3] == MPEG2_SEQ)
							{
								TUNER_STREAM_STRUCT * strm = _device_tuner_get_stream(tuner, packet->pid);
								if (!strm)
									strm = _device_tuner_add_stream(tuner, packet->pid);

//								if (strm && (!strm->type || tuner->reset_video_pids))
								if (strm && !strm->type)
								{
//									int as=0, fr = 0, br = 0;
									BITSTREAM *bs1 = bits_create((uint8_t *) &data[i+4], TS_PACKET_SIZE - 5 - i);
									if (bs1)
									{
										strm->type = MPEGTS_STREAM_TYPE_ISO13818_V;
										strm->width = bits_get_bit_count(bs1, 12, &rc);
										strm->height = bits_get_bit_count(bs1, 12, &rc);
										strm->aspect = bits_get_bit_count(bs1, 4, &rc);
										strm->fps = bits_get_bit_count(bs1, 4, &rc);
										strm->bitrate = bits_get_bit_count(bs1, 18, &rc);
										free(bs1);
									}
									tuner->video_pid = packet->pid;
//									tuner->reset_video_pids = 0;
									_dev_internal_printf(dev, "[DEVICE] [PID: 0x%x] Detected MPEG2 Video (%dx%d) a: %d, fps: %d, bitrate: %d\n", packet->pid, strm->width, strm->height, strm->aspect, strm->fps, strm->bitrate);
								}

								ret = packet->frame_type = 1;
								break;
							}
							else if (data[i+3] == 0x00)
							{
								fr_type = (uint8_t)(data[i+5] & 0x38) >> 3;

//								_dev_internal_printf(device, "MPEG2 FRAME: %s\n", MPEG2_PIC_TYPE[fr_type]);
								if (fr_type == 1)
								{
									ret = packet->frame_type = 1;
									break;
								}
							}
						}
						else if (tuner->video_es_type == MPEGTS_STREAM_TYPE_ISO14496_10)
						{
							BITSTREAM *bitstream = NULL;
							uint8_t *fixed = NULL;
							int fixed_sz = 0;
							uint8_t nal_type = data[i+3] & 0x1F;

//							printf("\tH264 Video\n");

							switch (nal_type)
							{
								case H264_NAL_SLICE:
								break;

								case H264_NAL_IDR:
									ret = packet->frame_type = 1;
//									printf("idr/slice\n");
								break;

								case H264_NAL_SEI:
//									printf("sei\n");
								break;

								case H264_NAL_SPS:
//								case H264_NAL_PPS:
								{
									fixed_sz = TS_PACKET_SIZE-i-4;
									fixed = calloc(1, fixed_sz);

									memcpy(fixed, &data[i+4], fixed_sz);
									_h264_unescape03(fixed, fixed_sz);
									bitstream = bits_create(fixed, fixed_sz);

									if (nal_type == H264_NAL_SPS)
									{
										H264_SEQ_PARAM_SET *sps =  _h264_parse_sps(bitstream);
										if (sps)
										{
											TUNER_STREAM_STRUCT * strm = _device_tuner_get_stream(tuner, packet->pid);
											if (!strm)
												strm = _device_tuner_add_stream(tuner, packet->pid);

//											if (strm && (!strm->type || tuner->reset_video_pids))
											if (strm && !strm->type)
											//if (strm)
											{
												uint64_t height = 0, width = 0;
												width = (sps->pic_width_in_mbs_minus1 + 1) * 16;
												height = (2 - sps->frame_mbs_only_flag) * (sps->pic_height_in_map_units_minus1+1) * 16;

												strm->type = tuner->video_es_type;
												strm->width = (uint32_t) width;
												strm->height = (uint32_t)height;

												if (sps && sps->vui_params)
												{
													if (sps->vui_params->aspect_ratio_info_present_flag)
													{
														if (sps->vui_params->aspect_ratio_idc == 1)
														{
															int norm = (int)floor((((double)width/(double)height)* 10));
															//printf("ANORM: %d\n", norm);
															switch (norm)
															{
																case 10:
																	strm->aspect = 1;
																break;

																case 13:
																	strm->aspect = 2;
																break;

																case 17:
																	strm->aspect = 3;
																break;
															}
														}
														//printf("\tASPECT: %d\n",  sps->vui_params->aspect_ratio_idc);
													}

													if (sps->vui_params->timing_info_present_flag)
													{
														int norm = (int)((double)sps->vui_params->time_scale / ((double)sps->vui_params->num_units_in_tick * 2) * 100);
														switch (norm)
														{
															case 2397:
																strm->fps = 1;
															break;

															case 2400:
																strm->fps = 2;
															break;

															case 2500:
																strm->fps = 3;
															break;

															case 2997:
															strm->fps = 4;
															break;

															case 3000:
																strm->fps = 5;
															break;

															case 5000:
																strm->fps = 6;
															break;

															case 6000:
																strm->fps = 7;
															break;
														}
													}
													if (sps->vui_params->nal_hrd_parameters_present_flag)
													{
														H264_HRD_PARAMS * h = sps->vui_params->nal_hrd_parameters;
														strm->bitrate = (uint32_t)floor((h->schedsel[0].bit_rate_value_minus1 + 1) * pow(2, 6 + h->bit_rate_scale));
//														printf("HAZ nal_hrd: %0.2f\n", tmp);
													}
												}
												//printf("w: %" PRId64" (%" PRId64"), H: %" PRId64" (%"PRId64")\n", width,  sps->pic_width_in_mbs_minus1 + 1, height, sps->pic_height_in_map_units_minus1 + 1);
												tuner->video_pid = packet->pid;
//												tuner->reset_video_pids = 0;
												_dev_internal_printf(dev, "[DEVICE] [PID: 0x%x] Detected H264 Video (%dx%d) a: %d, fps: %d, bitrate: %d\n", packet->pid, strm->width, strm->height, strm->aspect, strm->fps, strm->bitrate);
											}
											ret = packet->frame_type = 1;

											_h264_free_sps(sps);
										}
//										printf("sps\n");
									}
								}
								break;

								case H264_NAL_AUD:
								{
									uint8_t pp = data[i+4] >> 5;
//									printf("NAL: 0x%x %d\n", pp,pp);
									if (pp == H264_PPIC_I)
										ret = packet->frame_type = 1;

//									printf("aud\n");
								}
								break;
							}
							if (bitstream)
								free(bitstream);

							if (fixed)
								free(fixed);
/*
							if (nal_type == 0x09)
							{
							}
*/

						}
//							_dev_internal_printf(dev, "H264 Video, dev\n");
					}
				}
			}
			else if (bitstream && data && mpegts_streamtype_valid(psu->stream_id) == MPEGTS_TYPE_AUDIO)
			{
				int i = (bitstream->bit_offset/8);
				BITSTREAM *bs1 = NULL;
//				printf("AUDIO!!\n");

				if (pmt_type == MPEGTS_STREAM_TYPE_USER_DATA)
				{
					while(data[i] != AC3_START_CODE[0] && data[i+1] != AC3_START_CODE[1])
					{
						i++;
						if (i > TS_PACKET_SIZE - 3)
							break;
					}
					if (data[i] == AC3_START_CODE[0] && data[i+1] == AC3_START_CODE[1])
					{
						TUNER_STREAM_STRUCT * strm = _device_tuner_get_stream(tuner, packet->pid);
						if (!strm)
							strm = _device_tuner_add_stream(tuner, packet->pid);

							if (strm && !strm->type)
							{
//								printf("Process AC3 audio: 0x%x 0x%x\n", data[i], data[i+1]);
								strm->type = MPEGTS_STREAM_TYPE_USER_DATA;

								bs1 = bits_create((uint8_t *) &data[i+2], TS_PACKET_SIZE - 2 - i);
								if (bs1)
								{
									uint8_t acmod, fscod, frmsizcod, lfe;
									bits_get_bit_count(bs1,  16, &rc); //crc
									fscod = bits_get_bit_count(bs1,  2, &rc);
									frmsizcod = bits_get_bit_count(bs1,  6, &rc);
									bits_get_bit_count(bs1,  5, &rc);
									bits_get_bit_count(bs1,  3, &rc);
									acmod = bits_get_bit_count(bs1,  3, &rc);
									if((acmod & 0x1) && (acmod != 0x1))
										bits_get_bit_count(bs1,  2, &rc);

									if(acmod & 0x4)
										bits_get_bit_count(bs1,  2, &rc);

									if(acmod == 0x2)
										bits_get_bit_count(bs1,  2, &rc);
									lfe = bits_get_bit_count(bs1,  1, &rc); // lfe
									bits_get_bit_count(bs1,  5, &rc); // dialnorm

									strm->frame_size = AC3_FRAME_SIZE[frmsizcod][fscod] * 2;
									strm->bitrate = AC3_FRAME_SIZE[frmsizcod][3];
									strm->samplerate = AC3_FSCOD[fscod];

									switch(acmod)
									{
										case 1:
											strm->channels = 1;
										break;

										case 0:
										case 2:
											strm->channels = 2;
										break;

										case 3:
										case 4:
											strm->channels = 3;
										break;

										case 5:
										case 6:
											strm->channels = 4;
										break;

										case 7:
											strm->channels = 5;
										break;
									}
									if (lfe)
										strm->channels++;

									_dev_internal_printf(dev, "[DEVICE] [PID: 0x%x] Detected AC3 Stream [Channels: %d, SampleRate: %d, Bitrate: %d, FrmSz: %d]\n", packet->pid, strm->channels, strm->samplerate, strm->bitrate, strm->frame_size); 
								}
							}
					}
				}
				else if (pmt_type == MPEGTS_STREAM_TYPE_ISO13818_7) // AAC Audio
				{
					if (data[i] == AAC_START_CODE[0] && (data[i+1] & 0xF0) == AAC_START_CODE[1])
					{
						TUNER_STREAM_STRUCT * strm = _device_tuner_get_stream(tuner, packet->pid);
						if (!strm)
							strm = _device_tuner_add_stream(tuner, packet->pid);

							if (strm && !strm->type)
							{
								strm->type = MPEGTS_STREAM_TYPE_ISO13818_7;
								bs1 = bits_create((uint8_t *) &data[i], TS_PACKET_SIZE - i);
								if (bs1)
								{
									//uint16_t tmp16 = 0, frame_length = 0, number_of_raw_data_blocks_in_frame = 0, frames_in_packet = 0;
									uint16_t tmp16 = 0, frame_length = 0, number_of_raw_data_blocks_in_frame = 0;
									uint8_t tmp = 0, sampling_frequency_index=0;
									uint8_t chan_config = 0;

									tmp = (uint8_t) bits_get_bit_count(bs1, 8, &rc); // HEADER[0]
									tmp = (uint8_t) bits_get_bit_count(bs1, 4, &rc); // HEADER[1] (4), + start (4)

									tmp = (uint8_t) bits_get_bit_count(bs1, 1, &rc); // id
									tmp = (uint8_t) bits_get_bit_count(bs1, 2, &rc); // layer
									tmp = (uint8_t) bits_get_bit_count(bs1, 1, &rc); // protection_absent
									tmp = (uint8_t) bits_get_bit_count(bs1, 2, &rc); // profile
									sampling_frequency_index = (uint8_t) bits_get_bit_count(bs1, 4, &rc);  // sampling_frequency_index
									tmp = (uint8_t) bits_get_bit_count(bs1, 1, &rc); // private
									chan_config = (uint8_t) bits_get_bit_count(bs1, 3, &rc); //channel_config
									tmp = (uint8_t) bits_get_bit_count(bs1, 1, &rc); // original copy
									tmp = (uint8_t) bits_get_bit_count(bs1, 1, &rc); //home
	
									tmp = (uint8_t) bits_get_bit_count(bs1, 1, &rc);  //copyright_identification_bit
									tmp = (uint8_t) bits_get_bit_count(bs1, 1, &rc);  //copyright_identification_start
        							frame_length = (uint16_t) bits_get_bit_count(bs1, 13, &rc);
									if (frame_length < AAC_FIXED_HEADER_SIZE)
									{
										printf("AAC NOOOOOOOOOO\n");
									}

									tmp16 = (uint16_t) bits_get_bit_count(bs1, 11, &rc); // adts_buffer_fullness
									number_of_raw_data_blocks_in_frame = (uint8_t) bits_get_bit_count(bs1, 2, &rc);
									if (tmp && tmp16) {};

									strm->channels = chan_config;
									strm->bitrate = frame_length * BYTE_SIZE * AAC_SAMPLING_FREQ_INDEX[sampling_frequency_index] / ((number_of_raw_data_blocks_in_frame + 1) * 1024);
									strm->samplerate = AAC_SAMPLING_FREQ_INDEX[sampling_frequency_index];
									strm->frame_size = frame_length;
									_dev_internal_printf(dev, "[DEVICE] [PID: 0x%x] Detected AAC Stream [CH: %d, SampleR: %d, BitR: %d, FrmSz: %d]\n", packet->pid, strm->channels, strm->samplerate, strm->bitrate, strm->frame_size);
								}
							}

					}
					else
					{
						_dev_internal_printf(dev, "[DEVICE] [PID: 0x%x] AAC problem, header does not match PMT\n");
					}
				}
				else if (pmt_type == MPEGTS_STREAM_TYPE_ISO13818_3) // MP2 Audio
				{
					if (data[i] == MPEGAUDIO_START_CODE[0] && data[i+1] == MPEGAUDIO_START_CODE[1])
					{
						printf("Process MPEG audio: 0x%x 0x%x\n", data[i], data[i+1]);
					}
					else
					{
						_dev_internal_printf(dev, "[DEVICE] [PID: 0x%x] MPEGAUDIO problem, header does not match PMT\n");
					}
				}

				if (bs1)
					free(bs1);

			}
			else
			{
				printf("GOT HERE SOMEHOW\n");
			}
			if (!tuner->pts_dts_offset)
			{
//				_dev_internal_printf(device, "[%d] MOO: 0x%x\n", packet->pid, psu->stream_id);
				if (mpegts_streamtype_valid(psu->stream_id) == MPEGTS_TYPE_AUDIO)
				{
					if (psu->pts > CLOCK_90K)
					{
						tuner->pts_dts_offset = (psu->pts - 45000);
//						_dev_internal_printf(device, "[DEVICE] PTS/DTS Offset: %" PRId64" (%0.4fs) (Fix: %d)\n", tuner->pts_dts_offset, tuner->pts_dts_offset/90000.0, tuner->fix_stream);
					}
				}
			}
		}
		else
		{
//			printf("NOT VALID: PMT PID: 0x%02X, PID: 0x%02X, Valid: %d\n", tuner->pmt_pid, packet->pid, device_channel_pid_valid(tuner, packet->pid));
		}
//(tuner->pmt_pid && device_channel_pid_valid(tuner, packet->pid))

	}
	return ret;
}

uint8_t _device_process_payload(TUNER_STRUCT * tuner, uint8_t *data, uint32_t data_size)
{
	uint8_t ret = 0;

//	_dev_internal_printf(dev, "_device_process_payload start\n");
//	printf("_device_process_payload start\n");
	if (tuner && tuner->parent && data && data_size)
	{
		DEVICE_STRUCT * dev = (DEVICE_STRUCT *)tuner->parent;
		BITSTREAM *bitstream = bits_create(data, TS_PACKET_SIZE);

		if (bitstream)
		{
//				_dev_internal_printf(dev, "_device_process_payload pgm_num: %" PRId64"\n", tuner->pgm_num);
			MPEGTS_PACKET *packet = mpegts_parse_packet2(bitstream, &tuner->ts_parser);
			if (packet)
			{
				tuner->ts_parser.program_number = tuner->pgm_num;
//				_dev_internal_printf(dev, "_device_process_payload 1: 0x%x\n", packet->pid);
				if (packet->pid == PAT_PID)
				{
					_device_process_pat(dev, tuner, packet);
					tuner->pat_count++;
				}
				else if (tuner->pmt_pid && tuner->pmt_pid == packet->pid)
				{
					_device_process_pmt(dev, tuner, packet);
					tuner->pmt_count++;
				}
				else if (packet->payload_start && packet->payload_start_struct)
				{
					int8_t fr;
					packet->bitstream = bitstream;
					fr = _device_process_payload_start(dev, tuner, packet);

					if (fr != -1)
						ret = 1;
				}

//				_dev_internal_printf(device, "_device_process_payload 2\n");
				mpegts_free_packet(packet);
				if (tuner->ts_parser.pmt)
				{
					mpegts_free_pmt(tuner->ts_parser.pmt);
					tuner->ts_parser.pmt = NULL;
				}

				if (tuner->ts_parser.pat)
				{
					mpegts_free_pat(tuner->ts_parser.pat);
					tuner->ts_parser.pat = NULL;
				}
//				_dev_internal_printf(device, "_device_process_payload 3\n");

			}
			else
				ret = 2;

			free(bitstream);
		}
	}
	else
	{
		printf("_device_process_payload -- something not good\n");
	}
//	_dev_internal_printf(device, "_device_process_payload end\n");
	return ret;
}

int _device_process_protocol_cmd(TUNER_WRITEPASS_STRUCT *writepass)
{
//	uint64_t start_time = 0, now = 0;
	uint32_t old;
	time_t now, start_time;
	int ret = 1, err =0;
	if (writepass)
	{
		while(!writepass->command_socket)
		{
			printf("[DEV] Waiting for CMD socket\n");
			usleep(1000*1000);
		}

//		printf("_device_process_protocol_cmd 1\n");
		DEVICE_STRUCT * device = (DEVICE_STRUCT *)writepass->tuner->parent;
//			printf("_device_process_protocol_cmd 2\n");

		PROTOCOL_CMD_STRUCT * proto = protocol_get_cmd(writepass->client_socket);
//			printf("_device_process_protocol_cmd 3\n");

		if (proto)
		{
			uint32_t count=0;
			uint64_t _pos = MPEGTS_IO_INVALID;

//			printf("_device_process_protocol_cmd 1-A\n");
			if (proto->rc < 0)
			{
				_dev_internal_printf(device, "[DEVICE] protocol_get_cmd failed: %d -- die\n", proto->rc);
//				ret = proto->rc;
				protocol_free_cmd_struct(proto);
				protocol_send_tuner_pos(writepass->command_socket, _pos);
				return -1;
			}

//			printf("_device_process_protocol_cmd 1-B: 0x%x\n", proto->cmd);

			writepass->last_keepalive = (int64_t)time(NULL);
			start_time = time(NULL);
			switch (proto->cmd)
			{

				case PROTO_QUERY_STREAM_INFO:
				{
					TUNER_STRUCT *tuner = writepass->tuner;
//					printf("PROTO_QUERY_STREAM_INFO - start\n");
					if (tuner)
					{
						int i, rc;
						uint8_t count, wait, die = 0;
						TUNER_STREAM_STRUCT *send = NULL;
						while (tuner->valid_count == 0 || tuner->pmt_pid == 0 || tuner->video_pid == 0 || tuner->video_es_type == 0)
						{
							usleep(1000);
							now = time(NULL);
							if (now - start_time > 30)
							{
								die = 1;
								ret = -1;
								printf("PROTO_QUERY_STREAM_INFO done waiting: %d [%d %d]\n", tuner->valid_count, tuner->pmt_pid, tuner->video_pid);
								break;
							}
						}

						rc = 0;
//						printf("HERE1: 0x%x, 0x%x\n", tuner->video_pid, tuner->video_es_type);
						while (!die && tuner->streams_count < tuner->valid_count - 1)
						{
							for (i=0; i < tuner->valid_count; i++)
							{
								_dev_internal_printf(device, "device_channel_pid_valid: %d\n", tuner->valid_pids[i]);
							}

							printf("Sleep: %d -- %d\n", tuner->streams_count, tuner->valid_count);
							usleep(1000*500);
							rc++;

							if (rc > 1 && ((tuner->valid_count -1)  - tuner->streams_count)  == 1)
								break;


							now = time(NULL);
							if (now - start_time > 10)
							{
								die = 1;
								ret = -1;
								printf("PROTO_QUERY_STREAM_INFO done waiting2: %d [%d %d]\n", tuner->valid_count, tuner->pmt_pid, tuner->video_pid);
								break;
							}

//							if (i > 6)
//								break;
						}
//						printf("HERE2: 0x%x, 0x%x\n", tuner->video_pid, tuner->video_es_type);

//						printf("PROTO_QUERY_STREAM_INFO: %d, count: %d\n", tuner->tuned_channel, tuner->streams_count);

						for(i=0; i < tuner->streams_count; i++)
						{
//							printf("PID: 0x%x (%d) -- %d (last: %d)\n", tuner->streams[i].pid, tuner->streams[i].pid, tuner->streams[i].type, tuner->streams[i].is_last);
							tuner->streams[i].processed  = 0;
							tuner->streams[i].is_last  = 0;
						}

						wait = count = 0;
						// Find video
						while(!die && count < tuner->streams_count)
						{
							send = NULL;

							for(i=0; i < tuner->streams_count; i++)
							{
								if (tuner->streams[i].processed == 0)
								{
									if (tuner->streams[i].type == MPEGTS_STREAM_TYPE_ISO13818_V ||
										tuner->streams[i].type == MPEGTS_STREAM_TYPE_ISO14496_10)
									{
										send = &tuner->streams[i];
										break;
									}
									else if (tuner->streams[i].type == MPEGTS_STREAM_TYPE_USER_DATA ||
											tuner->streams[i].type == MPEGTS_STREAM_TYPE_ISO13818_7 ||
											tuner->streams[i].type == MPEGTS_STREAM_TYPE_ISO13818_3)
									{
										if (send)
										{
											if (tuner->streams[i].channels > send->channels || tuner->streams[i].bitrate > send->bitrate ||
												tuner->streams[i].frame_size > send->frame_size)
											{
												send = &tuner->streams[i];
											}
											else if (tuner->streams[i].iso639_lang[0] == 'e' && tuner->streams[i].iso639_lang[1] == 'n' &&
													tuner->streams[i].iso639_lang[2] == 'g' && send->iso639_lang[0] != 'e' &&
													send->iso639_lang[1] != 'n' && send->iso639_lang[2] != 'g')
											{
												send = &tuner->streams[i];
											}
											else if (tuner->streams[i].pid < send->pid)
											{
												send = &tuner->streams[i];
											}
										}
										else
										{
											send = &tuner->streams[i];
										}
									}
								}
							}

							now = time(NULL);
							if (now - start_time > 10)
							{
								die = 1;
								ret = -1;

								break;
							}

							if (!die)
							{
								if (send)
								{
									if (count + 1 >= tuner->streams_count)
										send->is_last = 1;
									send->processed = 1;
//									printf("PID: 0x%x (%d) -- %d (last: %d)\n", send->pid, send->pid, send->type, send->is_last);
									rc = write_bytes_to_socket(writepass->command_socket, (uint8_t *)send, sizeof(*send), 5000, NULL);
									if (rc != sizeof(*send))
										ret = -1;
									count++;
								}
								else
								{
									if(count < tuner->streams_count && tuner->streams_count - count == 1)
									{
										wait++;
										usleep(250*1000);
									}
									if (wait > 4)
									{
										TUNER_STREAM_STRUCT _send = {0};
										_send.is_last = 1;
										rc = write_bytes_to_socket(writepass->command_socket, (uint8_t *)&_send, sizeof(_send), 5000, NULL);
										if (rc != sizeof(_send))
											ret = -1;
										break;
									}
								}
							}
						}
					}
					else
						printf("Sadz2\n");

//					printf("PROTO_QUERY_STREAM_INFO - end\n");
				}
				break;

				case PROTO_KEEP_ALIVE:
//					_dev_internal_printf(device, "PROTO_KEEP_ALIVE\n");
//					writepass->last_keepalive = (int64_t)time(NULL);
				break;

				case PROTO_GET_STREAM_SZ_END_POS:
//					 _dev_internal_printf(device,"[GET] PROTO_GET_STREAM_SZ_END_POS -- Start\n");
					writepass->bad_cmd_count = 0;
					while (_pos == MPEGTS_IO_INVALID || _pos == 0)
					{
						count++;

						_pos = mpegts_io_get_reader_sz_endpos(writepass->reader);
						if (_pos == MPEGTS_IO_INVALID || _pos == 0)
							usleep(100*1000);
					}

					protocol_send_tuner_pos(writepass->command_socket, _pos);
//					 _dev_internal_printf(device,"[GET] PROTO_GET_STREAM_SZ_END_POS -- END\n");
				break;

				case PROTO_GET_STREAM_SZ_START_POS:
					writepass->bad_cmd_count = 0;
					_pos = 0;
					_dev_internal_printf(device, "[GET] PROTO, Get Stream Start SZ Pos: %" PRId64"\n", _pos);
					protocol_send_tuner_pos(writepass->command_socket, _pos);
				break;

				case PROTO_GET_STREAM_SZ_POS:
//					 _dev_internal_printf(device,"[GET] PROTO_GET_STREAM_SZ_POS -- Start\n");
					writepass->bad_cmd_count = 0;
//					_dev_internal_printf(device, "[GET] PROTO, Get Stream CURRENT SZ START\n");
					while (_pos == MPEGTS_IO_INVALID || _pos == 0)
					{
						count++;
						_pos = mpegts_io_get_reader_sz_pos(writepass->reader);
						if (_pos == MPEGTS_IO_INVALID)
						{
							printf("[DEV] POS (bytes) is invalid, waiting..\n");
						}
						else if (_pos == 0)
						{
							printf("[DEV] POS (bytes) is zero, setting to 1..\n");
							_pos = 1;
							break;
						}
						usleep(250*1000);
					}

//					_dev_internal_printf(device, "PROTO, Get Stream SZ Pos: %" PRId64"\n", _pos);
					protocol_send_tuner_pos(writepass->command_socket, _pos);
//					_dev_internal_printf(device,"[GET] PROTO_GET_STREAM_SZ_POS -- END\n");
				break;

				case PROTO_SET_STREAM_SZ_POS:
				{
//					 _dev_internal_printf(device,"[--SET] PROTO_SET_STREAM_SZ_POS -- Start\n");
					int rc = 0;
					uint8_t resp = 0;
					uint64_t end=0;
					uint64_t curtime = get_time_ms();

					writepass->bad_cmd_count = 0;

					old = writepass->packets_to_buffer;
//					writepass->packets_to_buffer = 0;

					end = MPEGTS_IO_INVALID;
					while(end == MPEGTS_IO_INVALID || end == 0)
					{
						end = mpegts_io_get_reader_sz_endpos(writepass->reader);

						if (end == MPEGTS_IO_INVALID || end == 0)
						{
							_dev_internal_printf(device, "[DEVICE] mpegts_io_get_reader_sz_endpos returned invalid, waiting\n");
							usleep(100*1000);
						}
					}

					_pos = *((uint64_t*)proto->dataptr);
					_dev_internal_printf(device, "[--SET] PROTO_SET_STREAM_SZ_POS, Seek to byte pos: %" PRId64", end: %" PRId64"\n", _pos, end);
/*
					if (curtime - writepass->last_seek_time >= 800 && _pos < end)
					{
						mpegts_io_set_reader_sz_pos(writepass->reader, _pos);
						_pos = mpegts_io_get_reader_sz_pos(writepass->reader);
						writepass->last_seek_time = curtime;
					}
					else
						_pos = MPEGTS_IO_INVALID;
*/
					mpegts_io_set_reader_sz_pos(writepass->reader, _pos);
					_pos = mpegts_io_get_reader_sz_pos(writepass->reader);
					if (_pos == 0)
						_pos = 1;

					writepass->last_seek_time = curtime;
//
//					printf("[--SET] PROTO_SET_STREAM_SZ_POS 3: %" PRId64"\n", _pos);
					protocol_send_tuner_pos(writepass->command_socket, _pos);
//					_dev_internal_printf(device, "[--SET] Waiting for client to tell me it's done flushing\n");
//					rc = get_bytes_from_socket(writepass->command_socket, (uint8_t*)&resp, 1, 3000, &err);
					rc = get_bytes_from_socket(writepass->command_socket, (uint8_t*)&resp, 1, 2000, &err);
					if (rc != 1)
					{
						// Error
					}
//					printf(	"[--SET] PROTO_SET_STREAM_SZ_POS 4\n");
					writepass->packets_to_buffer = old;

//					_dev_internal_printf(device, "[--SET] Done flushing: 0x%x -- old: %d -- inbuf: %d \n", resp, old, mpegts_io_get_packet_remaining(writepass->reader));
					while(mpegts_io_get_packet_remaining(writepass->reader) < writepass->packets_to_buffer)
					{
//						_dev_internal_printf(device, "[--SET] wait... %d %d\n", mpegts_io_get_packet_remaining(writepass->reader), writepass->packets_to_buffer);
						usleep(500*1000);
					}
//					 _dev_internal_printf(device,"[--SET] PROTO_SET_STREAM_SZ_POS -- END\n");
					writepass->seeked = 1;
				}
				break;

				case PROTO_GET_STREAM_END_POS:
				{
//					TUNER_STRUCT *tuner = writepass->tuner;
//					printf("PROTO_GET_STREAM_END_POS 1\n");
					writepass->bad_cmd_count = 0;
//					_dev_internal_printf(device, "MOO, tuner->streams_count: %d -- tuner->valid_count: %d\n", tuner->streams_count, tuner->valid_count);
					while (writepass->command_socket && writepass->client_socket && _pos == MPEGTS_IO_INVALID)
					{
						count++;
						_pos = mpegts_io_get_reader_endpos(writepass->reader);
						if (_pos == MPEGTS_IO_INVALID)
							usleep(50*1000);
/*
						end_time = (uint64_t)time(NULL);
						if (end_time - start_time > 5)
						{
							_dev_internal_printf(device, "[DEVIE] PROTO_GET_STREAM_END_POS has been invalid for more than 5 secs, exiting\n");
							break;
						}
*/
					}

//					_dev_internal_printf(device, "PROTO, Get Stream End Pos: (%d) -- %" PRId64" -- %0.4f\n",count, _pos, _pos/90000.0);
					protocol_send_tuner_pos(writepass->command_socket, _pos);
				}
				break;
/*
				case PROTO_GET_STREAM_START_POS:
					writepass->bad_cmd_count = 0;
					while (writepass->command_socket && writepass->client_socket && _pos == MPEGTS_IO_INVALID)
					{
						count++;
						_pos = mpegts_io_get_reader_startpos(writepass->reader);
						if (_pos == MPEGTS_IO_INVALID)
							usleep(50*1000);
					}
					_dev_internal_printf(device, "PROTO, Get Stream Start Pos: %" PRId64" -- %0.4f\n", _pos, _pos/90000.0);
					protocol_send_tuner_pos(writepass->command_socket, _pos);
				break;
*/
				case PROTO_GET_STREAM_START_POS2:
					writepass->bad_cmd_count = 0;
					while (writepass->command_socket && writepass->client_socket && _pos == MPEGTS_IO_INVALID)
					{
//						printf("PROTO_GET_STREAM_START_POS2 1\n");
						count++;
						_pos = mpegts_io_get_reader_startpos2(writepass->reader);
						if (_pos == MPEGTS_IO_INVALID)
						{
							usleep(250*1000);
						}
/*							usleep(50*1000);

						end_time = (uint64_t)time(NULL);
						if (end_time - start_time > 5)
						{
							_dev_internal_printf(device, "[DEVIE] PROTO_GET_STREAM_START_POS2 has been invalid for more than 5 secs, exiting\n");
							break;
						}
*/
//						printf("PROTO_GET_STREAM_START_POS2 2: %" PRId64"\n", _pos);
					}

					protocol_send_tuner_pos(writepass->command_socket, _pos);
				break;

				case PROTO_GET_STREAM_POS:
					writepass->bad_cmd_count = 0;
					while (writepass->command_socket && writepass->client_socket && _pos == MPEGTS_IO_INVALID)
					{
						count++;
						_pos = mpegts_io_get_reader_pos(writepass->reader);
						if (_pos == MPEGTS_IO_INVALID)
							usleep(250*1000);
/*
						end_time = (uint64_t)time(NULL);
						if (end_time - start_time > 5)
						{
							_dev_internal_printf(device, "[DEVIE] PROTO_GET_STREAM_POS has been invalid for more than 5 secs, exiting\n");
							break;
						}
*/
					}
//					_dev_internal_printf(device, "PROTO, Get Stream Pos (%d): %" PRId64" (%0.4f)\n",count, _pos, _pos/90000.0);
					protocol_send_tuner_pos(writepass->command_socket, _pos);
				break;

				case PROTO_SET_STREAM_POS:
				{
					int rc= 0;
					uint8_t offset = 0;
					uint64_t pos2, end;
//					double t_now=0, t_end=0, t_seekto=0;
					double t_now=0, t_end=0;
					uint64_t curtime = get_time_ms();

					printf("PROTO_SET_STREAM_POS\n");
					writepass->bad_cmd_count = 0;
					old = writepass->packets_to_buffer;
					writepass->packets_to_buffer = 0;
/*
					if (1)
					{
						pos2 = mpegts_io_get_reader_sz_pos(writepass->reader);
						end = mpegts_io_get_reader_sz_endpos(writepass->reader);
						_dev_internal_printf(device, "PROTO, Set Stream Pos SZ, current pos: %" PRId64", end: %" PRId64"\n", _pos, end);
					}
*/
					pos2 = mpegts_io_get_reader_pos(writepass->reader);
					end = mpegts_io_get_reader_endpos(writepass->reader);
					_pos = *((uint64_t*)proto->dataptr);
					
					t_now = (double)pos2/CLOCK_90K;
					t_end = (double)end/CLOCK_90K;

					_dev_internal_printf(device, "Set Stream Pos by Time, current pos: %" PRId64" (%0.2f), end: %" PRId64" (%0.2f) -- Set to POS: %" PRId64" (%0.2f)\n", pos2, t_now, end, t_end, _pos, _pos/90000.0);
					if (curtime - writepass->last_seek_time >= 250)
//					if (1)
					{
						while(writepass->command_socket && writepass->client_socket && end == MPEGTS_IO_INVALID)
						{
							_dev_internal_printf(device, "[DEVICE] mpegts_io_get_reader_endpos returned invalid, waiting\n");
							usleep(250*1000);
							end = mpegts_io_get_reader_endpos(writepass->reader);
						}

						if (t_now < t_end)
						{
							_pos = *((uint64_t*)proto->dataptr);

							if (_pos != MPEGTS_IO_LIVE_POS)
							{
								pos2 = _pos;

								if (pos2 < 90000)
								{
									_dev_internal_printf(device, "original req half a second or less, zero\n");
									pos2 = 90000;
								}
								//t_seekto = (double)pos2/CLOCK_90K;
							}
							else
							{
								_dev_internal_printf(device,"SET to LIVE!\n");
								pos2 = MPEGTS_IO_LIVE_POS;
							}

//							_dev_internal_printf(device,"Setting time pos to: %" PRId64" (%0.f) (o: %" PRId64"\n", _pos, _pos/90000, pos2);
							writepass->last_seek_time = curtime;

							if (pos2 == MPEGTS_IO_LIVE_POS || pos2 < end - 90000)
							{
								mpegts_io_set_reader_pos(writepass->reader, pos2);
								_pos = mpegts_io_get_reader_pos(writepass->reader);
//								_dev_internal_printf(device,"Set Pos Return: %ld (%0.4f)\n", _pos, _pos/90000.0);
							}
							else
							{
								_dev_internal_printf(device, "invalid?\n");
								_pos = MPEGTS_IO_INVALID;
							}
						}
						else
						{
							_dev_internal_printf(device, "1NOOOOOOO\n");
						}
					}
					else
					{
						_dev_internal_printf(device, "NOT SEEKING -- too soon\n");
						_pos = mpegts_io_get_reader_pos(writepass->reader);
//						_pos2 = MPEGTS_IO_INVALID;
					}

//					_dev_internal_printf(device, "Writing Return POS: %" PRId64" (%0.4f)\n", _pos, _pos/90000.0);
//					_dev_internal_printf(device, "Writing done\n");
					protocol_send_tuner_pos(writepass->command_socket, _pos);
//					rc = get_bytes_from_socket(writepass->command_socket, (uint8_t*)&offset, 1, 3000, &err);
					rc = get_bytes_from_socket(writepass->command_socket, (uint8_t*)&offset, 1, 250, &err);
					if (rc != 1)
					{
						// Error
					}
					writepass->packets_to_buffer = old;

//					_dev_internal_printf(device, "Done flushing: 0x%x -- old: %d -- inbuf: %d \n", offset, old, mpegts_io_get_packet_remaining(writepass->reader));
					while(mpegts_io_get_packet_remaining(writepass->reader) < writepass->packets_to_buffer)
					{
						_dev_internal_printf(device, "wait... %d %d\n", mpegts_io_get_packet_remaining(writepass->reader), writepass->packets_to_buffer);
						usleep(500*1000);
					}
					writepass->seeked = 1;
				}
				break;

				default:
					writepass->bad_cmd_count++;
//					_dev_internal_printf(device, "PROTO, Unhandled CMD: 0x%x\n", proto->cmd);
				break;
			}

			protocol_free_cmd_struct(proto);

			if (writepass->bad_cmd_count > 5)
			{
				_dev_internal_printf(device, "[DEVICE] Too man bad cmds, extiing\n");
				ret = -1;
			}
		}
		else
			printf("NO PROTO\n");
	}
	return ret;
}

int _device_recording_fill_info(TUNER_WRITEPASS_STRUCT *writepass)
{
//	printf("_device_recording_fill_info start\n");
	if (writepass && writepass->tuner && writepass->reader)
	{
		TUNER_STRUCT * tuner = writepass->tuner;
//		DEVICE_STRUCT * dev = (DEVICE_STRUCT *)tuner->parent;
		MPEGTS_IO_READER_STRUCT *reader = writepass->reader;
		uint64_t f_size = mpegts_io_get_reader_sz_endpos(reader);
		if (f_size)
		{
			int i;
			uint32_t pcount = 100, ret = 0;
//			printf("_device_recording_fill_info, f_size: %" PRId64"\n", f_size);
			reader->data = malloc(TS_PACKET_SIZE * pcount);
			if (reader->data)
			{
				do
				{
					ret = mpegts_io_get_packet_count(reader, pcount);

					for(i=0; i < ret; i += TS_PACKET_SIZE)
					{
						if (reader->data[i] == 0x47)
						{
							_device_process_payload(tuner, &reader->data[i], TS_PACKET_SIZE);
//							printf("_device_recording_fill_info: pat count: %" PRId64", pmt count: %" PRId64", valid count: %d\n", tuner->pat_count, tuner->pmt_count, tuner->valid_count);
							if (tuner->pat_count > 1 && tuner->pmt_count && tuner->valid_count)
							{
								int j, need_sync = 0;
								TUNER_STREAM_STRUCT * strm = NULL;
								for(j=0; j < tuner->valid_count; j++)
								{
									strm = _device_tuner_get_stream(tuner, tuner->valid_pids[j]);
									if (strm && strm->type)
									{
//										printf("M1: 0x%x (type: 0x%x)\n", tuner->valid_pids[j], strm->type);
										need_sync++;
									}
								}
								if (need_sync == tuner->valid_count - 1)
								{
									ret = 0;
									break;
								}
							}
						}
						else
						{
							printf("_device_recording_fill_info: need sync\n");
						}
					}
				}
				while (ret == (TS_PACKET_SIZE * pcount));
//				printf("OUT!!: pat count: %" PRId64", pmt count: %" PRId64", valid count: %d\n", tuner->pat_count, tuner->pmt_count, tuner->valid_count);
				free(reader->data);
			}
			mpegts_io_set_reader_pos(reader, 0);
		}

		return 1;
	}
	else
		printf("_device_recording_fill_info bad1\n");

	return 0;
}

//void *_device_write_thread(void *p)
void _device_write_thread(gpointer p, gpointer gdata)
{
//	printf("_device_write_thread start\n");
	if (p)
	{
		TUNER_WRITEPASS_STRUCT *writepass = (TUNER_WRITEPASS_STRUCT *)p;
		TUNER_STRUCT * tuner = writepass->tuner;
		DEVICE_STRUCT * dev = (DEVICE_STRUCT *)tuner->parent;
		int64_t last_status_update = 0, now = 0, last_packet_send = 0;
		uint8_t _ret = 0, die = 0;
		int write_ret = 0;
		uint32_t bytes_read = 0;
		int packets_avail = 0, packets_avail2 = 0;

		fd_set readfds;
		fd_set writefds;
		struct timeval tv = {0};
		int rc = 0;

//		uint64_t last_pts=0;

// 		_dev_internal_printf(dev, "wt1\n");
		writepass->write_status = TUNER_WRITE_STATUS_INIT;
		if (tuner->cb_gui_tuner_write_status)
			(*tuner->cb_gui_tuner_write_status)(writepass);

		while(!tuner->mpegts_io || !writepass->thread_index)
		{
/*
			if (!tuner->mpegts_io)
				_dev_internal_printf(device, "ED1\n");
			if (!writepass->thread_index)
				_dev_internal_printf(device, "ED2\n");
*/
			usleep(250*1000);
		}

 //		_dev_internal_printf(dev, "wt2\n");
		writepass->reader = mpegts_io_get_reader(tuner->mpegts_io, writepass->reader_type, writepass->time_pos);
//		_dev_internal_printf(device, "Unlocked\n");
		pthread_mutex_unlock(&tuner->write_thread_init_lock);

		if (!writepass->reader || writepass->client_socket < 1)
		{
			printf("_device_write_thread end1: %d %d\n", !!writepass->reader,  writepass->client_socket);
			return;
		}

		if (!writepass->packets_to_buffer)
			writepass->packets_to_buffer = __DATABUFFER_COUNT;

		printf("[DEVICE] Connection from: %s [%d] [0x%x]\n", writepass->ip_addr, writepass->stream_type, writepass->stream_type);
//		_dev_internal_printf(dev, "[DEVICE] Connection from: %s\n", writepass->ip_addr);
		switch (writepass->stream_type)
		{
			case TUNER_STREAM_TYPE_HTTP:
				_dev_internal_printf(dev, "[DEVICE] [HTTP] (buffer count: %d)\n", writepass->packets_to_buffer);
				write_ret = write_bytes_to_socket(writepass->client_socket, (uint8_t *)HTTP_OK_STR, HTTP_OK_STR_LEN, 5000, NULL);
			break;

			case TUNER_STREAM_TYPE_RECORDING:
			case TUNER_STREAM_TYPE_PROTOCOL:
			{
				struct sockaddr_storage addr = {0};
				socklen_t addrLen = sizeof(struct sockaddr_storage);
				uint16_t _listenport = dev->bind_port + 80 + tuner->id;
				int lsocket = -1;
				srand((int64_t)time(NULL));
				_listenport += (rand() % 256);
				write_ret = -1;
				writepass->write_status = TUNER_WRITE_STATUS_WAIT_CMD_SOCK;
				if (tuner->cb_gui_tuner_write_status)
					(*tuner->cb_gui_tuner_write_status)(writepass);

				while(lsocket < 1)
				{
					lsocket = get_listen_socket(dev->bind_ip, _listenport);
					if (lsocket < 1)
					{
						_dev_internal_printf(dev, "[DEVICE] Error Doing listen for cmd: %s (%d)\n", strerror(errno), errno);
						_listenport++;
						usleep(250*1000);
					}
				}

				if (writepass->stream_type == TUNER_STREAM_TYPE_PROTOCOL)
				{
					_dev_internal_printf(dev, "[DEVICE] [WT] Strm type: protocol (buf. count: %d, LPort: %d)\n", writepass->packets_to_buffer, _listenport);
				}
				else if (writepass->stream_type == TUNER_STREAM_TYPE_RECORDING)
				{
					int i;

					_device_recording_fill_info(writepass);
					_dev_internal_printf(dev, "[DEVICE] [WT] Strm type: recording (buf. count: %d, LPort: %d)\n", writepass->packets_to_buffer, _listenport);
//					_dev_internal_printf(dev, "\tPMT Pid: 0x%x\n", tuner->pmt_pid);
					for (i=0; i < tuner->valid_count; i++)
					{
						printf("\tValid PID: 0x%x", tuner->valid_pids[i]);
						if (tuner->valid_pids[i] != tuner->pmt_pid)
						{
							printf(" (Video/Audio)");
//							_device_tuner_add_stream(tuner, tuner->valid_pids[i]);
						}
						else
						{
							printf(" (PMT)");
						}
						printf("\n");

					}
				}

				write_ret = write_bytes_to_socket(writepass->client_socket, (uint8_t *)&_listenport, sizeof(uint16_t), 5000, NULL);

				if (write_ret == sizeof(uint16_t))
				{
					uint16_t count = 0;
//					printf("P1\n");
					do
					{
						tv.tv_sec = 4;

//						_dev_internal_printf(dev, "[DEVICE] [%d] Waiting for command socket..\n", count);
						FD_ZERO(&readfds);
						FD_SET(lsocket, &readfds);
						rc = select(lsocket+1, &readfds, NULL, NULL, &tv);

						if (rc > 0)
							writepass->command_socket = accept(lsocket, (struct sockaddr*) &addr, &addrLen);

						if (rc == 0)
							usleep(1000*1000);

						count++;

						if (count > 2)
							rc = -1;

					} while (rc == 0);

					if (lsocket > 0)
						close(lsocket);
				}

				if (writepass->command_socket)
				{
					die = 0;
					pthread_mutex_init(&writepass->command_mutex, NULL);
					pthread_mutex_init(&writepass->read_write_mutex, NULL);

//					pthread_mutex_lock(&writepass->command_mutex);
					while (pthread_mutex_trylock(&writepass->command_mutex) != 0)
					{
						printf("[DEVICE] waiting for command_mutex in _device_write_thread()\n");
						usleep(1000*250);
					}
					pthread_create(&writepass->command_thread, NULL, _device_command_thread, p);

					_dev_internal_printf(dev, "[DEVICE] [PROTO] CMD soc. connected, waiting for thread...");
					pthread_mutex_unlock(&writepass->command_mutex);
					_dev_internal_printf(dev, " got it, (buf. count: %d)\n", writepass->packets_to_buffer);
				}
				else
				{
					die = 1;
					_dev_internal_printf(dev, "[DEVICE] [PROTO] No command socket, dieing\n");
				}
			}
			break;

			default:
				_dev_internal_printf(dev, "[DEVICE] [WT] Stream type unknow... NOT GOOD\n");
			break;
		}

		if (!die)
		{
			writepass->write_status = TUNER_WRITE_STATUS_SEND_SPECIAL;
			if (tuner->cb_gui_tuner_write_status)
				(*tuner->cb_gui_tuner_write_status)(writepass);

			rc = write_bytes_to_socket(writepass->client_socket, (uint8_t *)SPECIAL_NULL_PACKET, TS_PACKET_SIZE, 5000, NULL);
			last_packet_send = (int64_t)time(NULL);

			if (tuner->writing <= -1)
				tuner->writing = 1;
			else
				tuner->writing++;

//			_dev_internal_printf(device, "[DEVICE] thread_index: %d -- %d %p\n", writepass->thread_index, writepass->client_socket, writepass->reader);

//			writepass->reader->data = calloc(1, (writepass->packets_to_buffer + 4) * TS_PACKET_SIZE);
			writepass->reader->data = malloc((writepass->packets_to_buffer + 4) * TS_PACKET_SIZE);

			while(writepass->client_socket > 2 && writepass->reader)
			{
				if (writepass->die || (tuner->tuned_channel == 0 && writepass->stream_type != TUNER_STREAM_TYPE_RECORDING))
				{
					_dev_internal_printf(dev, "[DEVICE] Writepass told me to die\n");
					break;
				}
				if (tuner->cb_write_data)
				{
//					_dev_internal_printf(device, "write_data\n");
					_ret = (*tuner->cb_write_data)(tuner);
					if (_ret == TUNER_EXIT_MSG)
						break;
				}

				FD_ZERO(&writefds);
				FD_SET(writepass->client_socket, &writefds);

				tv.tv_sec = 2;
				tv.tv_usec = 0;

				rc = select(writepass->client_socket + 1, NULL, &writefds, NULL, &tv);

//				printf("Select rc: %d\n", rc);
				if (rc <= 0)
				{
					if (rc < 0)
					{
						_dev_internal_printf(dev, "[DEVICE] WT error out, select is: %s (%d) -- %d\n", strerror(errno), errno, rc);
						break;
					}
					else
					{
						int64_t _now = (int64_t)time(NULL);
						writepass->write_status = TUNER_WRITE_STATUS_PAUSED;
						if (tuner->cb_gui_tuner_write_status)
							(*tuner->cb_gui_tuner_write_status)(writepass);

//						printf("Keealive info, now: %ld, last: %ld\n", _now, writepass->last_keepalive);
						if (writepass->last_keepalive && _now > writepass->last_keepalive && _now - writepass->last_keepalive > 15)
						{
							_dev_internal_printf(dev, "[DEVICE] WT timeout!, select is: %s (%d) -- %d\n", strerror(errno), errno, rc);
							break;
						}
					}
					continue;
				}

//				if (tuner->cb_gui_tuner_write_status)
//					(*tuner->cb_gui_tuner_write_status)(writepass, TUNER_WRITE_STATUS_WAIT_PACKETS);
				packets_avail = packets_avail2 = mpegts_io_get_packet_remaining(writepass->reader);
//				_dev_internal_printf(dev, "here2... %d -- %d\n", packets_avail, writepass->packets_to_buffer);


				if (packets_avail > writepass->packets_to_buffer)
					packets_avail =  writepass->packets_to_buffer;
/*
				if (writepass->packets_to_buffer == 0)
				{
					printf("Paused, reseting last packet send time\n");
					last_packet_send = (int64_t)time(NULL);
				}
*/
				if (packets_avail == 0)
				{
					if (writepass->stream_type == TUNER_STREAM_TYPE_RECORDING)
					{
						if (packets_avail2 == 0)
						{
							rc = write_bytes_to_socket(writepass->client_socket, (uint8_t *)SPECIAL_NULL_PACKET, TS_PACKET_SIZE, 5000, NULL);
							_dev_internal_printf(dev, "[DEVICE] ------------- Recording EOF: %d\n", rc);
							if (rc != TS_PACKET_SIZE)
							{
								if (rc == -1)
									break;
							}

//							usleep(1000*500);
							writepass->last_keepalive = (int64_t)time(NULL);
						}
						continue;
					}
					else
					{
						if (now - last_packet_send > 30 && !writepass->seeked)
						{
							_dev_internal_printf(dev, "NO DATA, exiting\n");
							break;
						}
						else
						{
							now = (int64_t)time(NULL);
							if (last_packet_send - now > 1)
							{
								rc = write_bytes_to_socket(writepass->client_socket, (uint8_t *)SPECIAL_NULL_STREAM_END, TS_PACKET_SIZE, 5000, NULL);
								if (rc < 0)
								{
									break;
								}
								else
								{
									writepass->last_keepalive = last_packet_send = (int64_t)time(NULL);
									//usleep(1000*100);
									_dev_internal_printf(dev, "_device_write_thread, no data?\n");
								}
							}
							else
							{
								usleep(1000*250);
							}
						}
						usleep(1000);
						continue;
					}
				}
				else
				{
					if (packets_avail > 1)
						packets_avail -= 1;
				}
/*
					_dev_internal_printf(dev, "KEEP Alive info, now: %d, last_alive: %d\n", now, writepass->last_keepalive);
				if (writepass->last_keepalive && now > writepass->last_keepalive && now - writepass->last_keepalive > 5)
				{
					_dev_internal_printf(dev, "KEEP Alive not sent, exiting, now: %d, last_alive: %d\n", now, writepass->last_keepalive);
					break;
				}
*/

//				printf("W6\n");
				bytes_read = mpegts_io_get_packet_count(writepass->reader, packets_avail);
//				printf("W7: %d\n", bytes_read);
/*
				if (writepass->seeked)
				{
					printf("HMMM: %" PRId64"\n", mpegts_io_get_reader_pos(writepass->reader));
					rc = write_bytes_to_socket(writepass->client_socket, (uint8_t *)SPECIAL_NULL_PACKET, TS_PACKET_SIZE, 5000, NULL);
//					writepass->seeked = 0;
				}
*/

				if (bytes_read)
				{
					size_t offset = 0;
					size_t write_sz = writepass->reader->data_len;
					now = (int64_t)time(NULL);

					if (!writepass->start_write_time)
						writepass->start_write_time = (int64_t)time(NULL);

					if (tuner->cb_gui_tuner_write_status && now - last_status_update >= 1)
					{
						writepass->write_status = TUNER_WRITE_STATUS_WRITING;
						(*tuner->cb_gui_tuner_write_status)(writepass);
						last_status_update = now;
					}

					if (tuner->cb_update_tuner_stats)
					{
						int64_t now = (int64_t)time(NULL);
						if (now - tuner->signal_last_update > 2)
						{
							if ((*tuner->cb_update_tuner_stats)(tuner))
							{
								uint8_t tmp[TS_PACKET_SIZE];
								tuner->signal_last_update = now;
//								printf("[DEVICE] Strength: %d, SNR: %d\n", tuner->signal_strength, tuner->signal_noise_ratio);
								memcpy(tmp, SPECIAL_NULL_PACKET_SIGNAL_INFO, TS_PACKET_SIZE);
								memcpy(&tmp[TS_PACKET_SIZE-4], &tuner->signal_strength, sizeof(uint16_t));
								memcpy(&tmp[TS_PACKET_SIZE-2], &tuner->signal_noise_ratio, sizeof(uint16_t));
								write_ret = write_bytes_to_socket(writepass->client_socket, tmp, TS_PACKET_SIZE, 5000, NULL);
							}
						}
					}

					do
					{
						if (offset)
						{
							_dev_internal_printf(dev, "[DEVICE] UGHHH: %" PRId64"\n", offset );
						}

						write_ret = write_bytes_to_socket(writepass->client_socket, writepass->reader->data + offset, write_sz, 5000, NULL);

						if ((int64_t)write_ret <= -1)
						{
							close(writepass->client_socket);
							writepass->client_socket = 0;
							break;
						}
						else if (write_ret == 0)
						{
							usleep(1000*100);
						}
						write_sz -= write_ret;
						offset += write_ret;
						writepass->bytes_written += write_ret;
					} while (offset < writepass->reader->data_len);

					if (write_ret <= 0)
					{
//						_dev_internal_printf(dev, "[DEVICE] writethread disconnected: %s\n", strerror(errno));
						break;
					}
					writepass->last_keepalive = last_packet_send = (int64_t)time(NULL);
					if (writepass->seeked)
						writepass->seeked = 0;
				}
				else
				{
					usleep(1000*100);
				}
			}
		}
/*
		if (writepass->stream_type == TUNER_STREAM_TYPE_RECORDING)
		{
			if (writepass->tuner->mpegts_io)
			{
				mpegts_io_close(writepass->tuner->mpegts_io, 0);
				writepass->tuner->mpegts_io = NULL;
			}
		}
*/
		if (writepass->reader)
		{
			if (writepass->reader->data)
				free(writepass->reader->data);

			mpegts_io_disconnect_reader(writepass->reader);
//	 		_dev_internal_printf(device, "[DEVICE] Exiting WT, reader_count: %d\n", writepass->reader->fileunit->reader_count);
			free(writepass->reader);
			writepass->reader = NULL;
		}


//		_dev_internal_printf(dev, "[DEVICE] exited write loop thread: %d\n", tuner->writing);

		last_packet_send = (int64_t)time(NULL);
		while (writepass->command_thread)
		{
			now = (int64_t)time(NULL);
			if (now - last_packet_send > 3)
			{
				_dev_internal_printf(dev, "[DEVICE] Time Expired, Forcing command thread to exit\n");
				if (writepass->client_socket)
					close(writepass->client_socket);
				writepass->client_socket = 0;
			}
			_dev_internal_printf(dev, "[DEVICE] waiting for command thread exit\n");
			usleep(250*1000);
		}

		writepass->write_status = TUNER_WRITE_STATUS_DONE;
		if (tuner->cb_gui_tuner_write_status)
			(*tuner->cb_gui_tuner_write_status)(writepass);

		if (writepass->client_socket)
		{
			close(writepass->client_socket);
			writepass->client_socket = 0;
		}

		if (writepass->command_socket)
		{
			close(writepass->command_socket);
			writepass->command_socket = 0;
		}

//		_dev_internal_printf(dev, "above msg should be command thread exited\n");

		pthread_mutex_unlock(&writepass->command_mutex);
		pthread_mutex_unlock(&writepass->read_write_mutex);
		pthread_mutex_destroy(&writepass->command_mutex);
		pthread_mutex_destroy(&writepass->read_write_mutex);

// 		_dev_internal_printf(dev, "[DEVICE] Exiting write thread\n");
		if (writepass->stream_type == TUNER_STREAM_TYPE_RECORDING)
		{
			if (writepass->tuner->mpegts_io)
			{
				mpegts_io_close(writepass->tuner->mpegts_io, 0);
/*
				//mpegts_io_close(writepass->tuner->mpegts_io, 0);
				if (tuner->mpegts_io->first_fileunit)
				{
					fclose(tuner->mpegts_io->first_fileunit->ts_fhandle);
					tuner->mpegts_io->first_fileunit->ts_fhandle = NULL;
				}
*/
			}

			if (writepass->tuner)
			{
				if (writepass->tuner->parent)
					free(writepass->tuner->parent);
				free(writepass->tuner);
			}
		}

		free(writepass); // free(p)

//		_dev_internal_printf(device, "[DEVICE] Exiting write thread: %d\n", tuner->writing);
		if (tuner->writing >= 1)
		{
			tuner->writing--;
			if (tuner->writing <= 0)
				writepass->die = 1;
		}
	}
//	printf("_device_write_thread exit\n");
			printf("_device_write_thread end2\n");
	return;
}

int _device_do_rec_stream_play(TUNER_INITPASS_STRUCT *parse_struct)
{
	if (parse_struct && (parse_struct->datasz == sizeof(MPEGTS_IO_STRUCT)))
	{
		TUNER_WRITEPASS_STRUCT *pass = calloc(1, sizeof(TUNER_WRITEPASS_STRUCT));
		TUNER_STRUCT * tuner = calloc(1, sizeof(TUNER_STRUCT));
		DEVICE_STRUCT * dev  = calloc(1, sizeof(DEVICE_STRUCT));

		if (pass && dev)
		{
//			printf("gg1\n");
			_dev_internal_printf(dev, "_device_do_rec_stream_play1 -- %d -- %" PRId64"\n", parse_struct->id, parse_struct->channel_num);
			dev->bind_port = 9997;
			tuner->parent = (void *)dev;
			tuner->mpegts_io = (MPEGTS_IO_STRUCT *)parse_struct->dataptr;
			pass->tuner = tuner;
			pass->client_socket = parse_struct->sock;
			pass->reader_type = MPEGTS_IO_READ_START;
			pass->time_pos = 0;
			pass->packets_to_buffer = 20;
			pass->stream_type = parse_struct->type;

//			printf("gg2\n");
//			_dev_internal_printf(device, "_device_do_rec_stream_play2\n");
//			pthread_create(&pass->write_thread, NULL, _device_write_thread, (void*)pass);

//			pthread_create(&pass->write_thread
			if (!tuner->write_thread_pool)
				tuner->write_thread_pool = g_thread_pool_new(_device_write_thread, (gpointer *)tuner, -1, FALSE, NULL );

			g_thread_pool_push (tuner->write_thread_pool, (gpointer)pass, NULL );
//			_dev_internal_printf(dev,"_device_do_rec_stream_play3\n");
			pass->thread_index = 1;
//			printf("gg3\n");

			while(pass->command_socket == 0 && !pass->die)
			{
				usleep(1000*250);
//				printf("HI\n");
			}
//			printf("gg4\n");

			parse_struct->dataptr = NULL;
			parse_struct->datasz = 0;
//			_dev_internal_printf(dev, "_device_do_rec_stream_play4\n");
		}

	}
	return -1;
}

int _device_do_tune_stream(DEVICE_STRUCT * device, TUNER_INITPASS_STRUCT *parse_struct)
{
	int rc = -1;
	TUNER_STRUCT *tuner = device_tuner_find(device, parse_struct->channel_num);

	if (tuner)
	{
		_dev_internal_printf(device, "Tuned Channel: %d\n", tuner->tuned_channel);
		if (!tuner->tuned_channel)
		{
			if (tuner->cb_tune_channel)
			{
				tuner->tuning = 1;
//				rc = (*tuner->cb_tune_channel)(tuner, parse_struct->channel_num);
				rc = (*tuner->cb_tune_channel)(tuner, parse_struct);
				switch(rc)
				{
					case 0: // Good
					break;
					case TUNER_TUNE_ERROR_NOCHAN:
						_dev_internal_printf(device, "[DEVICE] Tuning failed: Ch# %d, not in list/mapping\n", parse_struct->channel_num);
					break;
					case TUNER_TUNE_ERROR_UNKNOWN:
						_dev_internal_printf(device, "[DEVICE] Tuning failed: Unknown Error, Ch# %d\n", parse_struct->channel_num);
					break;
				}
				tuner->tuning = 0;
			}
		}
		else
		{
			rc = 0;
		}
	}

	if (rc != 0)
	{
		char error_str[1024] = {0};
//		_dev_internal_printf(device, "[DEVICE] rc is not zero: %d\n", rc);
		switch (rc)
		{
			case 2:
				strcpy(error_str, "HTTP/1.0 400 Channel Copy Flag is 0x02\r\n\r\n");
			break;

			case 1:
			case -1:
				strcpy(error_str, "HTTP/1.0 400 Out of Tuners (most likely)\r\n\r\n");
			break;

			case -2:
				strcpy(error_str, "HTTP/1.0 400 Channel Not Available\r\n\r\n");
			break;

			default:
				strcpy(error_str, "HTTP/1.0 400 Bad Request\r\n\r\n");
			break;
		}
//		_dev_internal_printf(device, "[DEVICE] Problem tuning, seding back: %s\n", error_str);
		rc = write_bytes_to_socket(parse_struct->sock, (uint8_t *)error_str, strlen(error_str), 5000, NULL);
		close(parse_struct->sock);
	}
	else
	{
//		printf("M1\n");
		if (tuner)
		{
			TUNER_WRITEPASS_STRUCT *pass = calloc(1, sizeof(TUNER_WRITEPASS_STRUCT));

//		printf("M2\n");
			memcpy(pass->ip_addr, parse_struct->ip_addr, INET_ADDRSTRLEN);
			pass->tuner = tuner;
			pass->client_socket = parse_struct->sock;
//		printf("M3\n");

			if (parse_struct->start_pos)
			{
//		printf("M4\n");

				pass->reader_type = MPEGTS_IO_READ_TIMECODE;
				pass->time_pos = parse_struct->start_pos;
			}
			else
			{
//		printf("M5\n");

				pass->reader_type = MPEGTS_IO_READ_LIVE;
				pass->time_pos = 0;
			}
			pass->packets_to_buffer = tuner->packets_to_buffer;
			pass->stream_type = parse_struct->type;
//		printf("M6\n");

			tuner->tuned_channel = parse_struct->channel_num;

//			pthread_mutex_lock(&tuner->write_thread_init_lock);
			while (pthread_mutex_trylock(&tuner->write_thread_init_lock) != 0)
			{
				printf("[DEVICE] waiting for write_thread_init_lock in _device_do_tune_stream()\n");
				usleep(1000*250);
			}
//		printf("M7\n");
//
//			pthread_create(&pass->write_thread, NULL, _device_write_thread, (void*)pass);
			g_thread_pool_push (tuner->write_thread_pool, (gpointer)pass, NULL );

			pass->thread_index = tuner->write_thread_count++;
//		printf("M8\n");

			pthread_mutex_unlock(&tuner->write_thread_init_lock);
//		printf("M9\n");

			// Launch writer thread here
			return 0;
		}
	}
	return -1;
}



//int _device_reload_channel_filter(TUNER_CHANNEL_FILTER_STRUCT *filter)
int device_reload_channel_filter(DEVICE_STRUCT * device)
{
#ifdef USE_GLIB
	TUNER_CHANNEL_FILTER_STRUCT *filter = device->channel_filter;
	if (filter)
	{
		UTILS_DATAPAIR_STRUCT *data_pair  = NULL;
		int read_file = 1;
		struct stat buffer;
		stat(filter->filename, &buffer);

		if (filter->mtime && filter->mtime == buffer.st_mtime)
			read_file = 0;

		if (read_file)
		{
			FILE *fp = fopen(filter->filename, "r");
			printf("[DEVICE] Reading channel file: %s\n", filter->filename);
			if (filter->filter_glist)
			{
				GSList *gs_tmp = g_slist_nth(filter->filter_glist, 0);
				printf("Flushing old list ");
				while(gs_tmp && gs_tmp->data)
				{
					printf(".");
					data_pair = gs_tmp->data;
					utils_free_datapair(data_pair);
					filter->filter_glist = g_slist_delete_link(filter->filter_glist, gs_tmp);
					gs_tmp = g_slist_next(gs_tmp);
				}
				printf("\n");
			}

			if (fp)
			{
				UTILS_DATAPAIR_STRUCT *data_pair = NULL;
				int chan_num = 0;

				char *xmltv_id = NULL;
				char *icon_url = NULL;
				char *display_name = NULL;

				TUNER_CHANNEL_STRUCT * chan;
				off_t sz = get_file_size(filter->filename);
				uint8_t *tmp_mem = calloc(1, sz);


				if (tmp_mem && fread(tmp_mem, sz, 1, fp))
				{
					TEXTFILE_IN_MEMORY *memf = memfile_init((char*)tmp_mem, (int)sz);
					if (memf)
					{
						int p;
						char *line = NULL;
						int line_count = memfile_getline_count(memf);
						for (p=0; p < line_count; p++)
						{
							line = memfile_getnext_line(memf, 1);

    		        	    if (line)
							{
								char tmp_display_name[256] = {0};
								char *tok = strtok(line,",");

								chan_num = atoi(tok);
								xmltv_id = strtok(NULL, ",");
								icon_url = strtok(NULL, ",");
								display_name = strtok(NULL, ",");
								if (!display_name)
									snprintf(tmp_display_name, sizeof(tmp_display_name) -1, "%d", chan_num);

//								printf("1HERE1: [%d] [%s] [%s] [%s]\n", chan_num, xmltv_id, icon_url, display_name);
								chan = device_channel_get_struct(device, chan_num, 0);
								if (chan)
								{
									data_pair = calloc(1, sizeof(UTILS_DATAPAIR_STRUCT));
									data_pair->data = calloc(1, sizeof(int));
									memcpy(data_pair->data, &chan_num, sizeof(int));

//							  		  printf("moo: %d\n", *((int*)data_pair->data));
									filter->filter_glist = g_slist_prepend(filter->filter_glist, data_pair);
									strncpy(chan->xmltv_id, xmltv_id, sizeof(chan->xmltv_id) -1);
									strncpy(chan->icon_url, icon_url, sizeof(chan->icon_url) -1);
									if (display_name)
										strncpy(chan->name, display_name, sizeof(chan->name) -1);
//									printf("Setting (%d) xmltv id: %s, icon: %s\n", chan_num, chan->xmltv_id, chan->icon_url);
								}
								xmltv_id = icon_url = display_name = NULL;
//								memset(xmltv_id, 0, sizeof(xmltv_id));
//								memset(icon_url, 0, sizeof(icon_url));
							}

						}
					}
				}
				if (tmp_mem)
					free(tmp_mem);
				fclose(fp);

/*
				while(fscanf(fp, "%d,%[^,],%[^,],%[^\n]", &chan_num, xmltv_id, icon_url, display_name) != EOF)
				{
//					int *tmp_num = NULL;
					printf("HERE1: [%d] [%s] [%s] [%s]\n", chan_num, xmltv_id, icon_url, display_name);
					chan = device_channel_get_struct(device, chan_num, 0);
					if (chan)
					{
						data_pair = calloc(1, sizeof(UTILS_DATAPAIR_STRUCT));
						data_pair->data = calloc(1, sizeof(int));
						memcpy(data_pair->data, &chan_num, sizeof(int));

//				  		  printf("moo: %d\n", *((int*)data_pair->data));
						filter->filter_glist = g_slist_prepend(filter->filter_glist, data_pair);
						strncpy(chan->xmltv_id, xmltv_id, sizeof(chan->xmltv_id) -1);
						strncpy(chan->icon_url, icon_url, sizeof(chan->icon_url) -1);
//						printf("Setting (%d) xmltv id: %s, icon: %s\n", chan_num, chan->xmltv_id, chan->icon_url);
					}

					memset(xmltv_id, 0, sizeof(xmltv_id));
					memset(icon_url, 0, sizeof(icon_url));

				}
*/

				filter->filter_glist = g_slist_reverse(filter->filter_glist);
				filter->mtime = buffer.st_mtime;
			}
		}
		else
		{
//			printf("NOT Reading file..\n");
		}
	}
	else
		printf("F2\n");
#endif
	return 0;
}

int _device_handle_main_connect(DEVICE_CONN_STRUCT *conn)
{
	int ret = -1;
#ifdef USE_GLIB
	if (conn)
	{
		DEVICE_STRUCT * device  = (DEVICE_STRUCT*)conn->device;
		TUNER_INITPASS_STRUCT *parse_struct = NULL;
//		TUNER_STRUCT *tuner = NULL;
		uint8_t close_sock = 1;
		char *time = NULL, *date = NULL;
//		char addr_buf[INET_ADDRSTRLEN] = {0};
		struct timeval tv = {0};
		int rc = -1;

		time = get_local_time();
		date = get_local_date();

		//printf("JJJJJJJJJJJ: %s\n", conn->addr_buf);
		memset(&tv, 0, sizeof(struct timeval));
		tv.tv_usec = 250 * 1000;

//		printf("_device_handle_main_connect 1\n");
		parse_struct = _device_parse_incoming_connection(device, conn->socket);
//		printf("_device_handle_main_connect 2\n");

		if (device->cb_gui_incoming_parse)
			(*device->cb_gui_incoming_parse)(conn->addr_buf, parse_struct->type, parse_struct->cmd);

		if (!parse_struct)
		{
			close(conn->socket);
			_dev_internal_printf(device, "Sadz\n");
			return -1;
		}
//		printf("_device_handle_main_connect 3\n");


		while (pthread_mutex_trylock(&device->process_cmd_mutex) != 0)
		{
//			printf("[DEVICE] waiting for process_cmd_mutex in _device_handle_main_connect(), cmd: 0x%x\n", parse_struct->cmd);
			usleep(1000*1000);
		}
//		printf("_device_handle_main_connect 4\n");

		parse_struct->sock = conn->socket;
		parse_struct->device = device;
		memcpy(parse_struct->ip_addr,  conn->addr_buf, INET_ADDRSTRLEN);

		ret = 0;
//		_dev_internal_printf(device, "\n[TUNER] Incoming Connection, CMD: %d (0x%x) [%s] (%s - %s)\n", parse_struct->cmd, parse_struct->cmd, conn->addr_buf, date, time);
//		_dev_internal_printf(device, "parse_cmd: 0x%x\n", parse_struct->cmd);
		if (time) free(time);
		if (date) free(date);
//		printf("_device_handle_main_connect 3\n");

		if (device->cb_wait)
		{
			while ((*device->cb_wait)(parse_struct))
			{
				_dev_internal_printf(device, "[TUNER] Told to wait, waiting...\n");
				usleep(1000*1000);
			}
		}
//		printf("_device_handle_main_connect 4\n");

		pthread_mutex_unlock(&device->process_cmd_mutex);

		switch (parse_struct->cmd)
		{
			case PROTO_INIT_CONNECTION:
			{
				uint8_t back = PROTOCOL_INIT_GOOD;
//				_dev_internal_printf(device, "PROTO_INIT_CONNECTION\n");
				rc = write_bytes_to_socket(parse_struct->sock, (uint8_t *)&back, sizeof(back), 5000, NULL);
				if (rc != sizeof(back))
					ret = -1;
			}
			break;


			case PROTO_RELOAD_EPG_FILE:
			{
				char *filename  = (char*)parse_struct->dataptr;
				_dev_internal_printf(device, "PROTO_RELOAD_EPG_FILE: %s\n", filename);
				if (device->cb_reload_epg)
					(*device->cb_reload_epg)(parse_struct);
			}
			break;

			case PROTO_GET_CHAN_EPG:
			{
//				char *chan  = (char*)parse_struct->dataptr;
//				_dev_internal_printf(device, "PROTO_GET_CHAN_EPG: %s\n", chan);
				if (device->cb_epg_chan)
					(*device->cb_epg_chan)(parse_struct);
			}
			break;


			case PROTO_TIMER_ADD:
			{
				uint8_t back = PROTOCOL_INIT_BAD;
				_dev_internal_printf(device, "PROTO_TIMER_ADD\n");
				if (device->cb_timer_add)
				{
				_dev_internal_printf(device, "PROTO_TIMER_ADD 1\n");

					if ((*device->cb_timer_add)(parse_struct) == 0)
						back = PROTOCOL_INIT_GOOD;
				_dev_internal_printf(device, "PROTO_TIMER_ADD 2\n");
				}
				_dev_internal_printf(device, "PROTO_TIMER_ADD 3\n");

				rc = write_bytes_to_socket(parse_struct->sock, (uint8_t *)&back, sizeof(back), 5000, NULL);
				if (rc != sizeof(back))
					ret = -1;

				_dev_internal_printf(device, "PROTO_TIMER_ADD 4\n");
			}
			break;

			case PROTO_TIMER_DEL:
			{
//				printf("moooooooooooooooooo\n");
				uint8_t	 back = PROTOCOL_INIT_BAD;
//				printf("BACK2, sock: %d, 0x%x (%d) rc: %d\n",parse_struct->sock,  back, rc);

				memcpy(&parse_struct->id, parse_struct->dataptr, parse_struct->datasz);

				back = PROTOCOL_INIT_GOOD;
				rc = write_bytes_to_socket(parse_struct->sock, (uint8_t *)&back, sizeof(back), 0, NULL);
				if (device->cb_timer_del)
				{
					if ((*device->cb_timer_del)(parse_struct) == 0)
					{
						back = PROTOCOL_INIT_GOOD;
						printf("del timer Callback good\n");
					}
					else
						printf("del timer Callback bad\n");

				}
//				printf("BACK2, sock: %d, 0x%x rc: %d\n",parse_struct->sock,  back, rc);
			}
			break;

			case PROTO_QUERY_TIMER_COUNT:
			{
//				_dev_internal_printf(device, "PROTO_QUERY_TIMER_COUNT - s\n");
				if (device->cb_timer_count)
					(*device->cb_timer_count)(parse_struct);
//				_dev_internal_printf(device, "PROTO_QUERY_TIMER_COUNT - e\n");
			}
			break;

			case PROTO_QUERY_TIMER_LIST:
//				_dev_internal_printf(device, "PROTO_TIMER_LIST - s\n");
				if (device->cb_timer_list)
					(*device->cb_timer_list)(parse_struct);
//				_dev_internal_printf(device, "PROTO_TIMER_LIST - e\n");
			break;


			case PROTO_GET_TIMER_SEQNUM:
//				_dev_internal_printf(device, "PROTO_GET_TIMER_SEQNUM -- start\n");
				if (device->cb_timer_seqnum)
					(*device->cb_timer_seqnum)(parse_struct);
//				_dev_internal_printf(device, "PROTO_GET_TIMER_SEQNUM -- end\n");
			break;

			case PROTO_GET_REC_SEQNUM:
//				_dev_internal_printf(device, "PROTO_GET_REC_SEQNUM\n");
				if (device->cb_rec_seqnum)
					(*device->cb_rec_seqnum)(parse_struct);
			break;


			case PROTO_QUERY_TUNER_COUNT:
			{
				int32_t c = device->tuner_count;
				rc = write_bytes_to_socket(parse_struct->sock, (uint8_t *)&c, sizeof(c), 5000, NULL);
				_dev_internal_printf(device, "[DEVICE] Returned tuner count: %d\n", c);
			}
			break;

			case PROTO_QUERY_CHANNEL_COUNT:
			{
				int32_t c = 0;
				if (device->cb_chan_count)
				{
					c = (*device->cb_chan_count)(parse_struct);
				}
				else
				{
					c = device_channel_get_count(device);
				}
				rc = write_bytes_to_socket(parse_struct->sock, (uint8_t *)&c, sizeof(c), 5000, NULL);
				if (rc != sizeof(c))
					ret = -1;

				_dev_internal_printf(device, "[DEVICE] Returned channel count: %d\n", c);
			}
			break;

			case PROTO_QUERY_CHANNEL_LIST:
			{
//				int i;
//				uint8_t type = 1;
				PROTOCOL_CHANNEL_STRUCT p_channel;

				if (device->cb_chan_list)
				{
					(*device->cb_chan_list)(parse_struct);
				}
				else
				{
					TUNER_CHANNEL_STRUCT * chan = device->first_channel_list;

					if (device->channel_filter)
					{
						if(device->channel_filter->type && file_exists(device->channel_filter->filename) == 0)
						{
							device_reload_channel_filter(device);
						}
					}

					switch(device->channel_filter->type)
					{
						case TUNER_CHANNEL_FILTER_INCLUDE:
							if (device->channel_filter->filter_glist)
							{
								UTILS_DATAPAIR_STRUCT *data_pair  = NULL;
								int tmp_count = 1;
								GSList *gs_tmp = device->channel_filter->filter_glist;
								GSList *gs_first = gs_tmp;

								while(gs_tmp && gs_tmp->data)
								{
									data_pair = gs_tmp->data;
									int tmp_num;
									memcpy(&tmp_num, data_pair->data, sizeof(int));
									//printf("HUH: %d (%d)\n",tmp_num, g_slist_length(device->channel_filter->filter_glist));

									if (tmp_num)
									{
//										printf("chan: %d [%d -- %d]\n", tmp_num, tmp_count, g_slist_length(gs_first));
										chan = device_channel_get_struct(device, tmp_num, 0);

										if (chan)
										{
											memset(&p_channel, 0, sizeof(PROTOCOL_CHANNEL_STRUCT));
											if (tmp_count == g_slist_length(gs_first))
												p_channel.is_last = 1;

											strncpy(p_channel.name, chan->name, sizeof(p_channel.name));
											strncpy(p_channel.icon_path, chan->icon_url, sizeof(p_channel.name));
											strncpy(p_channel.xmltv_id, chan->xmltv_id, sizeof(p_channel.name));

											p_channel.id = (int32_t)chan->virtual_channel;
											p_channel.num = (int32_t)chan->virtual_channel;

	//										snprintf(p_channel.icon_path, 8095, "%s", chan->info);
											rc = write_bytes_to_socket(parse_struct->sock, (uint8_t *)&p_channel, sizeof(PROTOCOL_CHANNEL_STRUCT), 5000, NULL);
											//printf("RC: %d\n", rc);
										}
										else
										{
											printf("[DEVICE] channel does not exist removing: %d\n", tmp_num);
										}

									}
									else
									{
										printf("tmpnum bad\n");
									}

									if (p_channel.is_last)
									{
										//printf("Exit here\n");
										break;
									}

									gs_tmp = g_slist_next(gs_tmp);
									tmp_count++;
								}
								//printf("device_reload_channel_filter -- 6\n");
							}
						break;

						case TUNER_CHANNEL_FILTER_EXCLUDE:
						case TUNER_CHANNEL_FILTER_NONE:
							while(chan)
							{
								memset(&p_channel, 0, sizeof(PROTOCOL_CHANNEL_STRUCT));
								if (chan->next == NULL)
									p_channel.is_last = 1;
								strncpy(p_channel.name, chan->name, sizeof(p_channel.name));
								strncpy(p_channel.xmltv_id, chan->xmltv_id, sizeof(p_channel.xmltv_id));
								strncpy(p_channel.icon_path, chan->icon_url, sizeof(p_channel.name));

								p_channel.id = (int32_t)chan->virtual_channel;
								p_channel.num = (int32_t)chan->virtual_channel;
								rc = write_bytes_to_socket(parse_struct->sock, (uint8_t *)&p_channel, sizeof(PROTOCOL_CHANNEL_STRUCT), 5000, NULL);

								chan = chan->next;
							}
						break;
					}
				}
			}
			break;

			case PROTO_QUERY_REC_COUNT:
//				_dev_internal_printf(device, "PROTO_QUERY_REC_COUNT\n");
				if (device->cb_rec_count)
					(*device->cb_rec_count)(parse_struct);
			break;

			case PROTO_QUERY_REC_LIST:
			{
//				_dev_internal_printf(device, "PROTO_QUERY_REC_LIST start\n");
				if (device->cb_rec_list)
					(*device->cb_rec_list)(parse_struct);
//				_dev_internal_printf(device, "PROTO_QUERY_REC_LIST end\n");
			}
			break;

			case PROTO_REC_PLAY:
//				_dev_internal_printf(device, "PROTO_QUERY_REC_PLAY\n");
				parse_struct->type = TUNER_STREAM_TYPE_RECORDING;
			case PROTO_REC_DEL:
			{
				if (device->cb_rec_play)
				{
					uint32_t id = 0;
					memcpy(&id, parse_struct->dataptr, parse_struct->datasz);

					if ((*device->cb_rec_play)(parse_struct) == 0)
					{
//						_dev_internal_printf(device, "PROTO_REC_PLAY/DEL start: (ch: %d, id: %d)\n", parse_struct->channel_num, parse_struct->id);

						if (parse_struct->dataptr && parse_struct->datasz)
						{
							TUNER_STRUCT *tuner = device_tuner_find(device, parse_struct->channel_num);
							_dev_internal_printf(device, "PROTO_REC_PLAY/DEL start: (ch: %d, id: %d)\n", parse_struct->channel_num, parse_struct->id);

//							_dev_internal_printf(device, "RecPlay state: %d\n", parse_struct->r_state);

							if (parse_struct->cmd == PROTO_REC_PLAY)
							{
								close_sock = 0;
								if (tuner && tuner->tuned_channel == parse_struct->channel_num &&
									parse_struct->r_state == TIMER_STATUS_BUSY)
								{
									MPEGTS_IO_STRUCT *tmpio = (MPEGTS_IO_STRUCT *)parse_struct->dataptr;
									if (tmpio && tmpio->first_fileunit && tmpio->first_fileunit->first_idx)
									{

										MPEGTS_IO_FILEUNIT_STRUCT  *fu = tmpio->first_fileunit;
//										printf("First IDX timecode: %" PRId64" -- %" PRId64"\n", fu->first_idx->pts, fu->first_idx->dts);
										if (fu->first_idx->dts)
											parse_struct->start_pos = fu->first_idx->dts;
										else
											parse_struct->start_pos = fu->first_idx->pts;
									}
									else
										parse_struct->start_pos = 0;

									_dev_internal_printf(device, "PROTO_REC_PLAYREC ALREADY TUNED!! [%" PRId64"]\n", parse_struct->start_pos);

									parse_struct->type = TUNER_STREAM_TYPE_PROTOCOL;
									parse_struct->cmd = PROTO_TUNE_AND_STREAM;
									parse_struct->dataptr = NULL;
									parse_struct->datasz = 0;
								}
								else
								{
									_dev_internal_printf(device, "PROTO_REC_PLAYREC 1!\n");
									_device_do_rec_stream_play(parse_struct);
								}
	//							_dev_internal_printf(device, "PROTO_REC_PLAYREC ID: %d\n", ();
//								_dev_internal_printf(device, "PROTO_REC_PLAYREC GOOD!\n");
							}
							else if (parse_struct->cmd == PROTO_REC_DEL)
							{
								if (device->cb_rec_del)
								{
//									uint8_t back = PROTOCOL_INIT_GOOD;
									parse_struct->dataptr = (uint8_t*)&id;
									parse_struct->datasz = sizeof(id);

									_dev_internal_printf(device,"PROTO_DEL_PLAYREC, id: %d\n", id);

									if (tuner && tuner->tuned_channel == parse_struct->channel_num &&
										parse_struct->r_state == TIMER_STATUS_BUSY)
									{
										_dev_internal_printf(device,"PROTO_DEL_PLAYREC -- STOPPING RECORDING, id: %d\n", parse_struct->id);
										if (device->cb_rec_stop)
											(*device->cb_rec_stop)(parse_struct);
									}
									_dev_internal_printf(device,"PROTO_DEL_PLAYREC3 -- DEL, id: %d\n", parse_struct->id);
									(*device->cb_rec_del)(parse_struct);
//									rc = write_bytes_to_socket(parse_struct->sock, (uint8_t *)&back, sizeof(back), 5000, NULL);

									parse_struct->dataptr = NULL;
									parse_struct->datasz = 0;

								}
							}
						}
						else
						{
//							_dev_internal_printf(device, "PROTO_REC_PLAYREC sadz!\n");
						}
					}
					else
					{
						_dev_internal_printf(device, "PROTO_REC_PLAYREC Bad!\n");
					}

				}
				else
					_dev_internal_printf(device, "************* no de\n");

			}
//			break;

			case PROTO_TUNE_AND_STREAM:
			{
				ret = -1;

//		printf("_device_handle_main_connect 10\n");
//						_dev_internal_printf(device, "M1\n");
				if (parse_struct->type == TUNER_STREAM_TYPE_PROTOCOL || parse_struct->type == TUNER_STREAM_TYPE_HTTP)
				{
					if (parse_struct->channel_num > 0)
					{
						if (parse_struct->cmd == PROTO_TUNE_AND_STREAM || parse_struct->type == TUNER_STREAM_TYPE_HTTP)
						{
//		printf("_device_handle_main_connect 11\n");

/*
							if (parse_struct->url_params)
								printf("GOO1: %s\n", parse_struct->url_params);
							else
								printf("BAD1\n");
*/
//							pthread_mutex_unlock(&device->process_cmd_mutex);
							close_sock = _device_do_tune_stream(device, parse_struct);
//		printf("_device_handle_main_connect 12\n");

						}
					}
				}
			}
			break;
			case 0:
				printf("GOt ZERO for cmd\n");
			break;
			default:
			break;
		}

//		printf("_device_handle_main_connect 5\n");
//		pthread_mutex_unlock(&device->process_cmd_mutex);

		if (close_sock)
		{
			close(conn->socket);
			if (conn->socket != parse_struct->sock)
				close(parse_struct->sock);
			conn->socket = 0;
//			conn->status = DEVICE_THREAD_STATE_SLEEP;
		}
//		printf("_device_handle_main_connect 6\n");

		if (parse_struct->dataptr)
		{
			free(parse_struct->dataptr);
		}
//		printf("_device_handle_main_connect done\n");
	}
#endif

	return ret;
}

int _device_handle_secondary_connect(DEVICE_STRUCT * device)
{
	return -1;
}

DEVICE_CONN_STRUCT *_device_get_conn_thread(DEVICE_STRUCT * device)
{
	if (device)
		return calloc(1, sizeof(DEVICE_CONN_STRUCT));
	return NULL;
}

void _device_conn_pool_thread(gpointer ldata, gpointer gdata)
{
//	printf("_device_conn_pool_thread start\n");
	if (ldata && gdata)
	{
//		DEVICE_STRUCT * device = (DEVICE_STRUCT *)gdata;
		DEVICE_CONN_STRUCT *conn = (DEVICE_CONN_STRUCT*)ldata;
		if (conn->socket && conn->device)
		{
			_device_handle_main_connect(conn);
		}
	}
//	printf("_device_conn_pool_thread end\n");
	return;
}


void *_device_accept_thread(void *p)
{
	DEVICE_STRUCT * device = (DEVICE_STRUCT *) p;
	DEVICE_CONN_STRUCT *tmp_conn = NULL;
//	struct timeval tv = {0};
	int rc = -1, flags, tmps;
	struct sockaddr_storage addr = {0};
	struct sockaddr_in *in  = (struct sockaddr_in *)&addr;
	socklen_t addrLen = sizeof(struct sockaddr_storage);

	if (!p)
	{
		_dev_internal_printf(device, "couldn't get device struct\n");
		return NULL;
	}

	device->listening = 1;

//	_dev_internal_printf(device, "[DEVICE] Waiting for tuners... [%d]\n", device->tuner_count);
	while(!device->tuner_count)
		usleep(700*1000);

	_dev_internal_printf(device, "[DEVICE] Found %d tuners!\n", device->tuner_count);


	while(device->listen_socket)
	{
		rc = select_wait_read(device->listen_socket, 2, 0);
		if (rc == 0)
		{
//			_dev_internal_printf(device, "Waiting for connection (%d)\n", device->tuner_count);
			usleep(250*1000);
			continue;
		}
		else if (rc < 0)
		{
//			_dev_internal_printf(device, "ACCEPT PROBLEMS!\n");
			close(device->listen_socket);
			device->listen_socket = 0;
			continue;
		}

		flags = fcntl(device->listen_socket, F_GETFL, 0);
		fcntl(device->listen_socket, F_SETFL, flags | O_NONBLOCK);
//		printf("_device_handle_main_connect start: %d\n", device->listen_socket);

		tmps = 0;
		tmp_conn = NULL;
		memset(&addr, 0, sizeof(struct sockaddr_storage));

		while (tmps == 0)
		{
//			printf("Accepting\n");
			tmps = accept(device->listen_socket, (struct sockaddr*) &addr, &addrLen);
			if (tmps <= 0)
			{
				if (errno == EWOULDBLOCK || errno == EAGAIN)
				{
					usleep(1000*250);
					tmps = 0;
					_dev_internal_printf(device, "[TUNER] accpet block, wait/try again\n");
					continue;
				}
				else
				{
//					device->connect_wait = 0;
					_dev_internal_printf(device, "[TUNER] Couldn't accpet, closing (%s -- %d)\n", strerror(errno), tmps);
					tmps = -1;
				}
			}
//			printf("Accepting dpne\n");
		}
		fcntl(device->listen_socket, F_SETFL, flags);


		tmp_conn = _device_get_conn_thread(device);
		if (tmp_conn)
		{
			inet_ntop(AF_INET, &(in->sin_addr), tmp_conn->addr_buf, INET_ADDRSTRLEN);
//			printf("HMMMMMMM: %s\n", tmp_conn->addr_buf);
			tmp_conn->device = device;
			tmp_conn->socket = tmps;
			g_thread_pool_push (device->glib_conn_thread_pool, (gpointer)tmp_conn, NULL );
		}
	}

	device->listening = 0;
	_dev_internal_printf(device, "[DEVICE] Exiting accept thread\n");
	return NULL;
}

TUNER_STREAM_STRUCT * _device_tuner_add_stream(TUNER_STRUCT *tuner, uint16_t pid)
{
	if (tuner && pid)
	{
		int i;
		for(i=0; i < TUNER_MAX_STREAMS; i++)
		{
			if (tuner->streams[i].pid == 0)
			{
				tuner->streams_count++;
				tuner->streams[i].pid = pid;
//				printf("_device_tuner_add_stream: 0x%x\n", pid);
				return &tuner->streams[i];
			}
		}
	}
	return NULL;

}

TUNER_STREAM_STRUCT * device_tuner_clear_streams(TUNER_STRUCT *tuner)
{
	if (tuner)
	{
		int i;

		tuner->streams_count = 0;
		for(i=0; i < TUNER_MAX_STREAMS; i++)
		{
			memset(&tuner->streams[i], 0, sizeof(tuner->streams[i]));
		}
	}
	return NULL;

}

TUNER_STREAM_STRUCT * _device_tuner_get_stream(TUNER_STRUCT *tuner, uint16_t pid)
{
	if (tuner && pid)
	{
		int i;
		for(i=0; i < tuner->streams_count; i++)
		{
			if (tuner->streams[i].pid == pid)
				return &tuner->streams[i];
		}
	}
	return NULL;

}

void *_device_process_thread(void *p)
{
#ifdef USE_GLIB
	if (p)
	{
		int q, bad_packet = 0;
		UTILS_DATAPAIR_STRUCT *data_pair  = NULL;
		DEVICE_STRUCT * dev = NULL;
		MPEGTS_IO_PACKET_STRUCT _tmp_io_packet = {0};
		TUNER_STRUCT * tuner = (TUNER_STRUCT *)p;
		uint64_t time_now = 0;
		uint64_t time_start = 0;

		do
		{
			dev = (DEVICE_STRUCT *)tuner->parent;
//			printf("Waiting for Parent\n");
			usleep(250 *1000);
		}
		while(!dev || !tuner->process_buffer_queue || !tuner->memlist_queue);

		g_async_queue_ref(tuner->process_buffer_queue);
		g_async_queue_ref(tuner->memlist_queue);

		while(tuner->alive)
		{
			if (tuner->writing <= 0)
			{
				time_start = time_now = 0;
				usleep(250 *1000);
				continue;
			}

			data_pair = g_async_queue_try_pop(tuner->process_buffer_queue);
			if (data_pair && tuner->mpegts_io)
			{
				MPEGTS_IO_PACKET_STRUCT *io_packet = NULL;
				bad_packet = 0;

				for (q=0; q < data_pair->data_size; q+= TS_PACKET_SIZE)
				{
					if (data_pair->data[q] == TS_SYNC_BYTE)
					{
//						TUNER_STREAM_STRUCT *stream = NULL;
						uint8_t start = (data_pair->data[q+1] & 0x40) >> 6;
						uint16_t pid = ((data_pair->data[q+1] & 0x1F) << 8) | data_pair->data[q+2];
//						printf("PID: %d, %d\n", pid, start);
//						uint8_t af = (data_pair->data[q+3] & 0x30) >> 4;
						uint8_t fr_type = 0;
//						uint8_t start_pos = 4;


						if (!tuner->pmt_pid && tuner->packet_count > 10000)
						{
							_dev_internal_printf(dev, "NOO, PAT_COUNT %" PRId64", PMT_COUNT: %" PRId64"\n", tuner->pat_count, tuner->pmt_count);
						}

						if (tuner->tuned_channel == 0)
						{
							printf("NO tune\n");
							continue;
						}

//						if (tuner->streams_count == 1 && tuner->pmt_count > 50)
						if (tuner->streams_count <= 1)
						{
							if (!time_start && tuner->writing)
								time_start = (uint64_t)time(NULL);

							time_now = (uint64_t)time(NULL);

							if (time_now - time_start > 5)
							{
//								printf("[DEVICE] Failed to get streams, quitting: %" PRId64"\n", tuner->streams_count);
//							printf("MOO2: %" PRId64" (%" PRId64" - %" PRId64")\n", time_now - time_start, time_now, time_start);
//								printf("NEED TO EXIT\n");
//								usleep(1000*1000);
								if (tuner->writing >= 1)
									tuner->writing = 0;
//								q = data_pair->data_size;
//								time_now = time_start = 0;
								continue;
							}

//							time_now = (uint64_t)time(NULL);
//							if (time_now - time_start > 5)
							{
//								printf("HERE (%" PRId64"): %" PRId64" -- %" PRId64"\n", time_now - time_start, tuner->streams_count, tuner->pmt_count);
							}
						}

						if (start)
						{
//						_dev_internal_printf(dev, "PID: 0x%x, start: %d\n", pid, start);

						 	fr_type = _device_process_payload(tuner, &data_pair->data[q], TS_PACKET_SIZE);
						}

						if (fr_type == 2)
						{
							_dev_internal_printf(dev, "[DEVICE] Skipping bad packet\n");
							continue;
						}

						if (tuner->pmt_pid && tuner->pts_dts_offset && (pid == PAT_PID || device_channel_pid_valid(tuner, pid)))
						{
							if (!tuner->mpegts_io->video_pid)
								tuner->mpegts_io->video_pid = tuner->video_pid;

							if (start)
							{
								io_packet = mpegts_io_parse_packet(&data_pair->data[q], TS_PACKET_SIZE, &_tmp_io_packet);
							}
							else
							{
								memset(&_tmp_io_packet, 0, sizeof(MPEGTS_IO_PACKET_STRUCT));

								io_packet = &_tmp_io_packet;
								io_packet->pid = pid;
								io_packet->data = &data_pair->data[q];
								io_packet->data_len = TS_PACKET_SIZE;
							}

							if (io_packet)
							{

								io_packet->frame_type = fr_type;
								mpegts_io_add_data(tuner->mpegts_io, io_packet);

								if (io_packet != &_tmp_io_packet)
									free(io_packet);

								io_packet = NULL;
								tuner->packet_count++;
							}
						}
						else
						{
//							printf("[%d] NOT Writing PID: %d\n", tuner->pmt_pid, pid);
						}
					}
					else
					{
						bad_packet++;
//						_dev_internal_printf(dev, "NO SYNC BYTE\n");
					}

//					if (bad_packet)
//						 _dev_internal_printf(dev, "BAD PACKETS: %d (%d)\n", bad_packet, q);
				}
			}
			else
			{
				usleep(1000 * 100);
//				_dev_internal_printf(dev, "BAD1\n");
			}

			if (data_pair && data_pair->data)
			{
				g_async_queue_push(tuner->memlist_queue, data_pair->data);
//				printf("memlist size: %d\n", g_async_queue_length(tuner->memlist_queue));
				free(data_pair);
//				if (!tuner->read_data_ptr)
//					tuner->read_data_ptr = malloc(tuner->read_size);
				
//				utils_free_datapair(data_pair);
			}
//			if (tuner->streams_count == 1)
//				time_start = 0;
		}
		g_async_queue_unref(tuner->process_buffer_queue);
		g_async_queue_unref(tuner->memlist_queue);

		tuner->process_thread = 0;
	}
#endif
//	printf("RET1\n");
	return NULL;
}


void *_device_read_thread(void *p)
{
#ifdef USE_GLIB
	if (p)
	{
		DEVICE_STRUCT * dev = NULL;
		TUNER_STRUCT * tuner = (TUNER_STRUCT *)p;
		uint8_t bad = 0;
		int64_t last_status_update = 0, now = 0;

		do
		{
			dev = (DEVICE_STRUCT *)tuner->parent;
//			_dev_internal_printf(device, "Waiting for Parent\n");
			usleep(250 *1000);
		}
		while(!dev);

//		_dev_internal_printf(dev, "[DEVICE] Starting device read thread [Name: %s] [ID: %d]\n", tuner->name, tuner->id);
//		_dev_internal_printf(dev, "Starting device read thread [Name: %s] [ID: %d]\n", tuner->name, tuner->id);

		while(tuner->alive)
		{
			if (!tuner->thread_id)
			{
//				pthread_mutex_lock(&dev->thread_init_mutex);
				while (pthread_mutex_trylock(&dev->thread_init_mutex) != 0)
				{
					printf("[DEVICE] waiting for thread_init_mutex in _device_read_thread()\n");
					usleep(1000*250);
				}
				tuner->thread_id = ++dev->thread_init_count;
				pthread_mutex_unlock(&dev->thread_init_mutex);
			}

			if (!tuner->process_buffer_queue)
			{
//				printf("Alloc new g_async_queue_new\n");
				tuner->process_buffer_queue = g_async_queue_new();
			}

			if (!tuner->memlist_queue && tuner->read_size)
			{
				int i;
				int count = __MEMLIST_BUFFER_COUNT/tuner->read_size;
				uint8_t *data = NULL;
//				printf("[DEVICE] Alloc memlist_queue (count: %d) --  %" PRId64"\n", count, tuner->read_size);
				tuner->memlist_queue = g_async_queue_new();
				for (i=0; i < count; i++)
				{
					data = malloc(tuner->read_size);
					g_async_queue_push(tuner->memlist_queue, data);
				}
			}

			if (!tuner->read_data_ptr && tuner->read_size)
			{
				tuner->read_data_ptr = g_async_queue_try_pop(tuner->memlist_queue);
				if (!tuner->read_data_ptr)
				{
//					printf("[DEVICE] allocate mem: %d\n", g_async_queue_length(tuner->memlist_queue));
					if (tuner->read_size)
						tuner->read_data_ptr = malloc(tuner->read_size);
					else
						tuner->read_data_ptr = NULL;
				}
			}

			if (!tuner->read_data_ptr && tuner->read_size)
			{
				_dev_internal_printf(dev, "Blahhdfwsh\n");
				usleep(250*1000);
				continue;
			}


			if (!tuner->tuned_channel)
			{
				UTILS_DATAPAIR_STRUCT *data_pair = NULL;
				tuner->bytes_read = 0;
				tuner->start_read_time = 0;

				data_pair = g_async_queue_try_pop(tuner->process_buffer_queue);

				while (data_pair)
				{
//					printf("HERE!!\n");
					utils_free_datapair(data_pair);
					data_pair = g_async_queue_try_pop(tuner->process_buffer_queue);
				}

				tuner->read_status = TUNER_READ_STATUS_IDLE;
				if (tuner->cb_gui_tuner_read_status)
					(*tuner->cb_gui_tuner_read_status)(tuner);

				usleep(250*1000);
				continue;
			}

			if (!tuner->mpegts_io)
			{
				char _tmp[MAX_FILENAME_SIZE] = {0};
				char _bdir[MAX_FILENAME_SIZE] = {0};
				MPEGTS_IO_INIT_ARGS_STRUCT tmpopts;

				snprintf(_tmp, MAX_FILENAME_SIZE, "_%05" PRId64"_%li", tuner->tuned_channel, (int64_t)time(NULL));

				tuner->read_status = TUNER_READ_STATUS_TUNING;
				if (tuner->cb_gui_tuner_read_status)
					(*tuner->cb_gui_tuner_read_status)(tuner);

				if (tuner->segment_dir)
				{
					if (tuner->segment_dir[strlen(tuner->segment_dir)] == '/')
						tuner->segment_dir[strlen(tuner->segment_dir)] = '\0';

					snprintf(_bdir, MAX_FILENAME_SIZE, "%s/", tuner->segment_dir);
				}
				else
				{
					snprintf(_bdir, MAX_FILENAME_SIZE, "%s/", ".");
				}

				if (tuner->base_filename)
					strncat(_bdir, tuner->base_filename, MAX_FILENAME_SIZE-2);
				else
					strncat(_bdir, "ts_buffer", MAX_FILENAME_SIZE-2);

				if (tuner->mpegts_fileunit_maxsize > 0)
					strncat(_bdir, _tmp, MAX_FILENAME_SIZE-2);

				memcpy(&tmpopts, &tuner->io_opts, sizeof(MPEGTS_IO_INIT_ARGS_STRUCT));
				memset(&tuner->io_opts, 0, sizeof(MPEGTS_IO_INIT_ARGS_STRUCT));

				tuner->io_opts.extra_data2 = tmpopts.extra_data2;
				tuner->io_opts.cb_seek_to_time = tmpopts.cb_seek_to_time;
				tuner->io_opts.cb_get_current_time = tmpopts.cb_get_current_time;
				tuner->io_opts.cb_get_start_time = tmpopts.cb_get_start_time;
				tuner->io_opts.cb_get_end_time = tmpopts.cb_get_end_time;

				tuner->io_opts.filename_base = _bdir;
				tuner->io_opts.max_segment_size = tuner->mpegts_fileunit_maxsize;
				tuner->io_opts.max_segment_life = tuner->mpegts_fileunit_maxlife;
				tuner->io_opts.mode = MPEGTS_IO_MODE_CREATE;

				tuner->io_opts.write_cache_size = tuner->mpegts_fileunit_cachesize;

				tuner->io_opts.stream_only = dev->stream_only;
				tuner->mpegts_io = mpegts_io_init(&tuner->io_opts);

				if (tuner->mpegts_io)
				{
//					_dev_internal_printf(dev, "[DEVICE] Created mpegts_io [%s] (sz: %d, life: %d, stream only: %d)\n", _tmp, tuner->mpegts_io->max_file_size,tuner->mpegts_io->max_file_life, tuner->io_opts.stream_only);
				}
				else
				{
					_dev_internal_printf(dev, "[DEVICE] Borken mpegts_io\n");
					continue;
				}
				tuner->read_status = TUNER_READ_STATUS_TUNED;

				if (tuner->cb_gui_tuner_read_status)
					(*tuner->cb_gui_tuner_read_status)(tuner);
			}

			if (tuner->writing == 0)
			{
				int i;
				MPEGTS_IO_STRUCT *io_del = NULL;
				uint8_t del_files = 0;
				printf("_device_read_thread locking tunerlock\n");
				while (pthread_mutex_trylock(&dev->tunerlock) != 0)
				{
					printf("[DEVICE] waiting for tunerlock in _device_read_thread()\n");
					usleep(1000*250);
				}


				if (tuner->cb_close_data)
					(*tuner->cb_close_data)(tuner);

				if (tuner->mpegts_io)
				{
					if (tuner->mpegts_fileunit_maxsize > 0)
						del_files = 1;

					io_del = tuner->mpegts_io;
					if (io_del)
					{
						printf("[DEVICE] _device_read_thread free mpegts_io() start\n");
						mpegts_io_close(io_del, del_files);
						printf("[DEVICE] _device_read_thread free mpegts_io() end\n");
					}
				}
				tuner->mpegts_io = NULL;

				tuner->fix_stream = 1;
				tuner->haz_data = 0;
				tuner->writing = -1;
				tuner->pid_msg = 0;
				tuner->packet_count = 0;
				tuner->pat_count = 0;
				tuner->pmt_count = 0;
				tuner->streams_count = 0;

				for(i=0; i < TUNER_MAX_STREAMS; i++)
					memset(&tuner->streams[i], 0, sizeof(TUNER_STREAM_STRUCT));

				for(i=0; i < MAX_VALID_PIDS; i++)
				{
					tuner->valid_pids_type[i] = 0;
					tuner->valid_pids[i] = 0;
				}
				tuner->pts_dts_offset = tuner->pgm_num = tuner->pmt_pid = tuner->video_pid = 0;
				tuner->video_es_type = tuner->audio_es_type  = tuner->valid_count = 0;

				memset(&tuner->ts_parser, 0, sizeof(MPEGTS_PARSE_STRUCT));

				_dev_internal_printf(dev, "[DEVICE] No more write streams, stopping the read: %d\n", tuner->id);
				tuner->tuned_channel = 0;
				printf("_device_read_thread unlocking tunerlock\n");
				pthread_mutex_unlock(&dev->tunerlock);

//				_dev_internal_printf(dev, "[DEVICE] 11No more write streams, stopping the read: %d\n", tuner->id);

				continue;
			}

			bad = 1;

			if (tuner->cb_read_data)
			{
				while(tuner->tuning)
				{
					printf("[DEVICE] waiting for tuning to finish...\n");
					usleep(500 * 1000);
				}
//				printf("Readin...\n");
				bad = (*tuner->cb_read_data)(tuner);

				if (!bad && tuner->process_buffer_queue)
				{
					UTILS_DATAPAIR_STRUCT *data_pair = malloc(sizeof(UTILS_DATAPAIR_STRUCT));

					//FILE *fp = fopen("test1.mpg", "a+");
					//fwrite(tuner->read_data_ptr, tuner->read_size, 1, fp);
					//fclose(fp);
					data_pair->data = tuner->read_data_ptr;
					data_pair->data_size = tuner->read_size;

					now = (int64_t)time(NULL);

					if (!tuner->start_read_time)
						tuner->start_read_time = now;

					tuner->read_status = TUNER_READ_STATUS_READING;
					if (tuner->cb_gui_tuner_read_status && now - last_status_update >= 1)
					{
						(*tuner->cb_gui_tuner_read_status)(tuner);
						last_status_update = now;
					}

					g_async_queue_push(tuner->process_buffer_queue, data_pair);
					tuner->bytes_read += tuner->read_size;
					tuner->read_data_ptr = NULL;
//					send_tuner_stats = 0;

				}
				else
				{
					if (bad == DEVICE_READ_NODATA)
					{
						_dev_internal_printf(dev, "ACK, no data?: %d -- %d\n", bad, !!tuner->process_buffer_queue);
						usleep(1000*1000);
					}
					else
					{
						_dev_internal_printf(dev, "ACK, bad: %d -- %d\n", bad, !!tuner->process_buffer_queue);
						if (tuner->writing >= 1)
							tuner->writing = 0;
					}
					continue;
				}
			}
		}

		if (tuner->process_buffer_queue)
		{
//			g_async_queue_unref(tuner->process_buffer_queue);
			tuner->process_buffer_queue = NULL;
		}
		if (tuner->memlist_queue)
		{
//			g_async_queue_unref(tuner->memlist_queue);
			tuner->memlist_queue = NULL;
		}

		if (tuner->read_data_ptr)
		{
			free(tuner->read_data_ptr);
			tuner->read_data_ptr = NULL;
		}

		tuner->thread_id = 0;
		dev->thread_init_count = 0;
//		_dev_internal_printf(dev, "[DEVICE] read thread exiting: [%s] [%d]\n", tuner->name, tuner->id);
		tuner->read_thread = 0;
	}
#endif
	return NULL;
}

void *_device_command_thread(void *p)
{
	if (p)
	{
		TUNER_WRITEPASS_STRUCT *writepass = (TUNER_WRITEPASS_STRUCT *)p;
		fd_set readfds;
		struct timeval tv = {0};
		int rc = 0;

		pthread_mutex_unlock(&writepass->command_mutex);

		while(writepass->client_socket > 2 && writepass->reader)
		{
//			printf("_device_command_thread, socket : %d\n", writepass->client_socket);
			FD_ZERO(&readfds);
			FD_SET(writepass->client_socket, &readfds);

			tv.tv_sec = 2;
			tv.tv_usec = 0;

//			printf("_device_command_thread 2\n");
			rc = select(writepass->client_socket + 1, &readfds, NULL, NULL, &tv);
//			printf("_device_command_thread 3: %d\n", rc);

//			printf("cmd thread rc: %d\n", rc);
			if (rc == 0)
			{
//				printf("_device_command_thread, rc is zero\n");
				continue;
			}

			else if (rc < 0)
			{
//				printf("_device_command_thread, rc is less than zero\n");
//				printf("HI1: %d\n", rc);
				break;
			}
//			printf("_device_command_thread 4\n");

			if (_device_process_protocol_cmd(writepass) == -1)
			{
//				_dev_internal_printf(dev, "Recover from bad proto. maybe\n");
//				close(writepass->client_socket);
//				writepass->client_socket = 0;
//				printf("HI2: %d\n", rc);
				break;
			}
//			printf("_device_command_thread 5\n");
		}

		printf("[DEVICE] Exiting command thread\n");
// 		_dev_internal_printf(dev, "[DEVICE] Exiting command thread\n");
		writepass->die = 1;
		writepass->command_thread = 0;
	}
	return NULL;
}


#ifdef _MAIN_
static const char *optString = "a:m:d:c:i:p:T:t:?h";

static const struct option longOpts[] =
{
	{ "device", required_argument, NULL, 'd' },
	{ "cetonip", required_argument, NULL, 'a' },
	{ "timeout", optional_argument, NULL, 't' },
	{ "tunertype", optional_argument, NULL, 'T' },
	{ "count", optional_argument, NULL, 'c' },
	{ "port", optional_argument, NULL, 'p' },
	{ "ip", optional_argument, NULL, 'i' },
	{ "chan", optional_argument, NULL, 'k' },
	{ "max", optional_argument, NULL, 'm' },
	{ "help", no_argument, NULL, 'h' },
	{ NULL, no_argument, NULL, 0 }
};
void display_usage(char *exe)
{
	fprintf(stderr,"bleah\n");
}


uint8_t get_opts(int argc, char *const argv[])
{
	int index = 0;
	int opt = getopt_long( argc, argv, optString, longOpts, &index );

	if (opt == -1 )
	{
		display_usage(argv[0]);
		return 1;
	}
	while ( opt != -1 )
	{
		switch ( opt )
		{
			case 'i':
//				bind_ip = optarg;
				break;

			case 'p':
//				bind_port = atoi(optarg);
				break;

			case 'c':
//				max_devcount = atoi(optarg);
				break;

			case 't':
//				timeout_ms = atoi(optarg);
				break;

			case 'T':
//				tuner_type = atoi(optarg);
				break;

			case 'm':
//				max_devcount = atoi(optarg);
				break;

			case 'a':
//			 	hdhr_dev = ceton_ip = optarg;
				break;

			case 'd':
//				device_to_open = optarg;
				break;

			case 'k':
//				hdhr_channels_file = optarg;
				break;

			case 'h': 
			case '?':
				display_usage(argv[0]);
				break;

			default:
				break;
		}
		opt = getopt_long( argc, argv, optString, longOpts, &index );
	}
	return 0;
}


int main(int argc, char * argv[])
{
	return -1;
}
#endif
